C# – How to check if a type has a default constructor

A default constructor is a constructor that doesn’t have parameters.

Therefore, to check if a type has a default constructor, you can use reflection to loop through the constructors and see if there are any with no parameters, like this:

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

In this article I’ll show an example of loading types that implement a specific interface – IPlugin – and only load them if they have a default constructor.

IPlugin interface

public interface IPlugin
{
	string HandlesDataFromSource { get; }
	void ProcessData(string data);
}

Loading the IPlugin types with default constructors

The following code gets all IPlugin types in the current assembly, then creates an instance if the type has a default constructor.

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);
}

Note: It’s creating a routing table based on what the plugin says it can handle.

Three default constructor scenarios

FileSystemDataHandler plugin – has compiler-generated default constructor

When you don’t declare a constructor, the compiler automatically creates a default constructor for you. When I run the code, it’ll load this plugin because it has a default constructor.

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

	public void ProcessData(string data)
	{
		//process data
	}
}

HttpDataHandler plugin – has user-defined declared default constructor

In this class I declared a constructor that has no parameters – therefore it’s a default constructor, and this plugin will be loaded when I run the code.

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);
	}
}

SqlDataHandler plugin – no default constructor

The following plugin has a constructor with parameters, which means it doesn’t have a default constructor. Because it doesn’t have a default constructor, it will not be loaded.

public class SqlDataHandler : IPlugin
{
	private ConnectionStringSettings ConnectionStringSettings;

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

	public string HandlesDataFromSource => "Sql";

	public void ProcessData(string data)
	{
		//process data
	}
}

Results

Running the code results in the following output. As you can see it doesn’t load SqlDataHandler (because it doesn’t have a default constructor, therefore it’s filtered out).

Loading plugins that have a default constructor

Leave a Comment