C# – So überprüfen Sie, ob ein Typ einen Standardkonstruktor hat

C# – So überprüfen Sie, ob ein Typ einen Standardkonstruktor hat

Ein Standardkonstruktor ist ein Konstruktor, der keine Parameter hat.

Um zu überprüfen, ob ein Typ einen Standardkonstruktor hat, können Sie daher die Reflektion verwenden, um die Konstruktoren zu durchlaufen und zu sehen, ob es welche ohne Parameter gibt, wie hier:

private static bool HasDefaultConstructor(Type type)
{
	return type.GetConstructors().Any(t => t.GetParameters().Count() == 0);
}
Code language: C# (cs)

In diesem Artikel zeige ich ein Beispiel für Ladetypen, die eine bestimmte Schnittstelle implementieren – IPlugin – und sie nur laden, wenn sie einen Standardkonstruktor haben.

IPlugin-Schnittstelle

public interface IPlugin
{
	string HandlesDataFromSource { get; }
	void ProcessData(string data);
}
Code language: C# (cs)

Laden der IPlugin-Typen mit Standardkonstruktoren

Der folgende Code ruft alle IPlugin-Typen in der aktuellen Assembly ab und erstellt dann eine Instanz, wenn der Typ über einen Standardkonstruktor verfügt.

static void Main(string[] args)
{
	var candidateTypes = GetAllTypesThatImplementInterface<IPlugin>();

	Dictionary<string, IPlugin> routingTable = new Dictionary<string, IPlugin>();

	foreach(var type in candidateTypes)
	{
		if(HasDefaultConstructor(type))
		{
			var plugin = (IPlugin)Activator.CreateInstance(type);
			routingTable.Add(plugin.HandlesDataFromSource, plugin);
			Console.WriteLine($"Created type {type.Name}");

		}
		else
		{
			Console.WriteLine($"Not creating type {type.Name} - it doesn't have a default constructor");
		}
	}
}

private static bool HasDefaultConstructor(Type type)
{
	return type.GetConstructors().Any(t => t.GetParameters().Count() == 0);
}

private static IEnumerable<Type> GetAllTypesThatImplementInterface<T>()
{
	return System.Reflection.Assembly.GetExecutingAssembly()
	  .GetTypes()
	  .Where(type => typeof(T).IsAssignableFrom(type) && !type.IsInterface);
}
Code language: C# (cs)

Hinweis:Es erstellt eine Routing-Tabelle basierend auf dem, was das Plug-in verarbeiten kann.

Drei standardmäßige Konstruktor-Szenarien

FileSystemDataHandler-Plugin – hat einen vom Compiler generierten Standardkonstruktor

Wenn Sie keinen Konstruktor deklarieren, erstellt der Compiler automatisch einen Standardkonstruktor für Sie. Wenn ich den Code ausführe, wird dieses Plugin geladen, da es einen Standardkonstruktor hat.

public class FileSystemDataHandler : IPlugin
{
	public string HandlesDataFromSource => "FileSys";

	public void ProcessData(string data)
	{
		//process data
	}
}
Code language: C# (cs)

HttpDataHandler-Plugin – hat einen benutzerdefinierten deklarierten Standardkonstruktor

In dieser Klasse habe ich einen Konstruktor deklariert, der keine Parameter hat – daher ist es ein Standardkonstruktor, und dieses Plugin wird geladen, wenn ich den Code ausführe.

public class HttpDataHandler : IPlugin
{
	public string HandlesDataFromSource => "Http";

	public void ProcessData(string data)
	{
		//process data
	}
	private HashSet<string> wordFilterSet;
	public HttpDataHandler()
	{
		var wordFilterList = ConfigurationManager.AppSettings["wordFilter"].Split(',');
		wordFilterSet = new HashSet<string>(wordFilterList);
	}
}
Code language: C# (cs)

SqlDataHandler-Plugin – kein Standardkonstruktor

Das folgende Plugin hat einen Konstruktor mit Parametern, was bedeutet, dass es keinen Standardkonstruktor hat. Da es keinen Standardkonstruktor hat, wird es nicht geladen.

public class SqlDataHandler : IPlugin
{
	private ConnectionStringSettings ConnectionStringSettings;

	public SqlDataHandler(ConnectionStringSettings connectionStringSetting)
	{
		ConnectionStringSettings = connectionStringSetting;
	}

	public string HandlesDataFromSource => "Sql";

	public void ProcessData(string data)
	{
		//process data
	}
}
Code language: C# (cs)

Ergebnisse

Das Ausführen des Codes führt zu der folgenden Ausgabe. Wie Sie sehen können, wird SqlDataHandler nicht geladen (weil es keinen Standardkonstruktor hat und daher herausgefiltert wird).