Create generic class with internal constructor
Is it possible to construct an object with its internal constructor within a generic method?
public abstract class FooBase { }
public class Foo : FooBase {
internal Foo() { }
}
public static class FooFactory {
public static TFooResult Cr开发者_高级运维eateFoo<TFooResult>()
where TFooResult : FooBase, new() {
return new TFooResult();
}
}
FooFactory
resides in the same assembly as Foo
. Classes call the factory method like this:
var foo = FooFactory.CreateFoo<Foo>();
They get the compile-time error:
'Foo' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TFooType' in the generic type or method 'FooFactory.CreateFoo()'
Is there any way to get around this?
I also tried:
Activator.CreateInstance<TFooResult>();
This raises the same error at runtime.
You could remove the new()
constraint and return:
//uses overload with non-public set to true
(TFooResult) Activator.CreateInstance(typeof(TFooResult), true);
although the client could do that too. This, however, is prone to runtime errors.
This is a hard problem to solve in a safe manner since the language does not permit an abstract constructor declaraton.
The type argument must have a public parameterless constructor. When used together with other constraints, the new() constraint must be specified last.
http://msdn.microsoft.com/en-us/library/d5x73970.aspx
edit: so no, if you use new() constraint, you cannot pass that class, if you don't use new() constraint you can try using reflection to create new instance
public static TFooResult CreateFoo<TFooResult>()
where TFooResult : FooBase//, new()
{
return (TFooResult)typeof(TFooResult).GetConstructor(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] {}, null).Invoke(new object[]{});
//return new TFooResult();
}
There can be few work-arounds as below but I don't think you want to go that way!
Put switch statement inside Factory that will create the instance based on type of type parameter.
Each concrete implementation of FooBase will register with FooFactory passing the factory method to create it self. So FooFactory will use the internal dictionary
Extending on the similar line except mapping between type parameter and concrete implementation would be external code (xml file, configuration etc). IOC/DI containers can also help here.
public class GenericFactory
{
public static T Create<T>(object[] args)
{
var types = new Type[args.Length];
for (var i = 0; i < args.Length; i++)
types[i] = args[i].GetType();
return (T)typeof(T).GetConstructor(types).Invoke(args);
}
}
精彩评论