I'm trying to build a factory method that uses the generics feature of C#.
In this factory method I would like to constraint it to some specific classes, all of which do not have a default constructor.
Here is my example. Can someone tell me if it's possible to run it?
public class AbstractClass {
//this abstract class does not have a default constructor, nor its subclasses
public AbstractClass(SomeClassName obj) {
//use obj for initialization
}
}
//this factory class should create objects of type T that inherit
//from AbstractClass and invoke the non-default constructor
public class FactoryClass {
public static T BuildObject<T> (SomeClassName obj) where T: AbstractClass {
return new T(obj); //does not work?!?!?!
}
}
//Edit: ANSWER!!!
public static T BuildObject<T>(SomeClassUsedForTheConstructor item) where T : SomeAbstractClass {
return (T) Activator.CreateInstance(typeof (T), item);
}
I like to use Activator.CreateInstance(typeof(T)) in my generics that need to create new objects of type T. It works really well.
Look at the Type class and GetConstructor. Once you get the ConstructorInfo object, use the Invoke Method.
var x = typeof(T);
var t = x.GetConstructor(new[] {obj.GetType()});
object u = t.Invoke(<inputs>);
I don't think you can instantiate generic types without a default constructor on the constraint type.
Consider instead specifying an interface IAbstractClass, such that your factory class can set the SomeClassName parameter as a property of IAbstractClass.
Additionally, if a SomeClassName instance is required for initializing AbstractClass, consider also having an empty default constructor, but a rich initializer method defined in IAbstractClass. For example:
public interface IAbstractClass { void Initialize(SomeClassName obj); }
That way, your static BuildObject method instead does:
public static T BuildObject<T>(SomeClassName obj) where T: AbstractClass
{
T newObject = new T();
IAbstractClass ac = newObject as IAbstractClass;
ac.Initialize(obj);
}
No, what you are trying to do is not possible using the built-in generic constraints alone. The new keyword only allows you to constrain the generic type to having a default constructor.
Related
I need to instatiate a C# type dynamically, using reflection. Here is my scenario: I am writing a base class, which will need to instantiate a certain object as a part of its initialization. The base class won't know what type of object it is supposed to instantiate, but the derived class will. So, I want to have the derived class pass the type to the base class in a base() call. The code looks something like this:
public abstract class MyBaseClass
{
protected MyBaseClass(Type myType)
{
// Instantiate object of type passed in
/* This is the part I'm trying to figure out */
}
}
public class MyDerivedClass : MyBaseClass
{
public MyDerivedClass() : base(typeof(Whatever))
{
}
}
In other words, the base class is delegating to its derived type the choice of the object type to be instantiated.
Can someone please assist?
Try Activator.CreateInstance(Type)
http://msdn.microsoft.com/en-us/library/wccyzw83.aspx
You're looking for Activator.CreateInstance
object instance = Activator.CreateInstance(myType);
There are are various overloads of this method that can take constructor arguments or other information to find the type (such as names in string form)
http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx
You might want to use generics instead:
public abstract class MyBaseClass<T> where T : new()
{
protected MyBaseClass()
{
T myObj = new T();
// Instantiate object of type passed in
/* This is the part I'm trying to figure out */
}
}
public class MyDerivedClass : MyBaseClass<Whatever>
{
public MyDerivedClass()
{
}
}
The where T : new() is required to support the new T() construct.
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 CreateFoo<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);
}
}
Is there any way to do code such this:
class GenericClass<T>
{
void functionA()
{
T.A();
}
}
Or, how to call a function of type parameter (type is some my custom class).
Re:
T.A();
You can't call static methods of the type-parameter, if that is what you mean. You would do better to refactor that as an instance method of T, perhaps with a generic constraint (where T : SomeTypeOrInterface, with SomeTypeOrInterface defining A()). Another alternative is dynamic, which allows duck-typing of instance methods (via signature).
If you mean that the T is only known at runtime (as a Type), then you would need:
typeof(GenericClass<>).MakeGenericType(type).GetMethod(...).Invoke(...);
To call a method of a generic type object you have to instantiate it first.
public static void RunSnippet()
{
var c = new GenericClass<SomeType>();
}
public class GenericClass<T> where T : SomeType, new()
{
public GenericClass(){
(new T()).functionA();
}
}
public class SomeType
{
public void functionA()
{
//do something here
Console.WriteLine("I wrote this");
}
}
I think you are looking for generic type constraints:
class GenericClass<T> where T : MyBaseClass
{
void functionA<T>(T something)
{
something.A();
}
}
In terms of the code you posted - in order to call something on T, you will need to pass it as a parameter to functionA. The constraint you use will have to ensure that any T has an A method that can be used.
I understand from your code that you want to call a type parameter static method, and that's just impossible.
See here for more info : Calling a static method on a generic type parameter
I've got an abstract class like this;
public abstract PropertyBase
{
public static System.Type GetMyType()
{
return !!!SOME MAGIC HERE!!!
}
}
I'd like to subclass it, and when I call the static GetMyType(), I'd like to return the subclass's type. So if I declare a subtype;
public class ConcreteProperty: PropertyBase {}
then when I call
var typeName = ConcreteProperty.GetMyType().Name;
I expect 'typeName' to be set to "ConcreteProperty." I suspect there's no way to do it, but I'm interested if anyone out there knows a way to get this info.
(The particular problem I'm trying to solve is the verbosity of dependency properties in WPF; I'd love to be able to do something like this;
class NamedObject : DependencyObject
{
// declare a name property as a type, not an instance.
private class NameProperty : PropertyBase<string, NamedObject> { }
// call static methods on the class to read the property
public string Name
{
get { return NameProperty.Get(this); }
set { NameProperty.Set(this, value); }
}
}
And I almost have an implementation, but I can't quite get the info I need out of my NameProperty class.)
You can partially achieve (1-level of inheritance deep) using generics:
class PropertyBase<T>
{
public static Type GetMyType() { return typeof (T); }
}
// the base class is actually a generic specialized by the derived class type
class ConcreteProperty : PropertyBase<ConcreteProperty> { /* more code here */ }
// t == typeof(ConcreteProperty)
var t = ConcreteProperty.GetMyType();
The subclassing bit will not work, because a static method is tied to a type. It is a method of a type, not a method of an instance. The subtype does not contain the static methods of a base type, because they are different types and the static method is tied to the base type. Even though the compiler might allow you to call a static method of a base class as through a derived class, it will in reality call the method from the base class. It's just syntax sugar. For the same reason you cannot "override" static methods in subclasses because it would make little sense.
Just wondering why would need to do something like this?
var typeName = ConcreteProperty.GetMyType().Name;
Anyhow you know the type while calling the method, you can simply do this as well..
var typeName = typeof(ConcreteProperty).Name;
Just in case you need to do this, you can use "shadowing" to override the implementation of base class in child class.
public class ConcreteProperty : PropertyBase {
public new static Type GetMyType {
//provide a new implementation here
}
}
Ok I have a generic interface
public IConfigurationValidator<T>
{
void Validate();
}
a class that implements it:
public class SMTPServerValidator : IConfigurationValidator<string>
{
public void Validate(string value)
{
if (string.IsNullOrEmpty(value))
{
throw new Exception("Value cannot be null or empty");
}
}
}
I now want to use reflection to create an instance of SMTPServerValidator, because I know the AssemblyQualifiedName of the type.
I was thinking to use Activator.CreateInstance and cast that to the interface...
like this:
IConfigurationValidator<T> validator = (IConfigurationValidator<T>)Activator.CreateInstance(typeof(SMTPServerValidator));
I dont know what T is....how do I use reflection to create an instance of this class?
There is another class that has that I am dealing with that I left out:
public class ConfigurationSetting<T>
{
IConfigurationValidator<T> m_Validator;
public ConfigurationSetting(IConfigurationValidator<T> validator)
{
m_Validator = validator;
}
public void Validate(T value)
{
m_Validator.Validate(value);
}
}
In the end I am trying to create ConfigurationSettings and need to pass in the appropriate validator based on the parameter.
Creating the instance of the class is easy - you've done that already with Activator.CreateInstance.
If you don't know what T is, how are you hoping to use this as an implementation of the interface?
I assume that in reality, the interface actually refers to T in the members. If it doesn't - or if you don't need those bits - then make it non-generic, or create a non-generic base interface which the base interface extends.
In the example given, T is string. Is this what you mean?
The class you want to cast to is IConfigurationValidator<string>, as the SMTPServerValidator implements IConfigurationValidator<T>, specifying T as string
How about
Type lConfigValidatorType = typeof(IConfigurationValidator<>)
Type lSomeOtherType = typeof(T)
Type lConstructedType = lConfigValidatorType.MakeGenericType(lSomeOtherType);
var lObject = Activator.CreateInstance(lConstructedType)
I realized at a higher layer I do have the type and can create it the way I was initially intending to do.