2

[NOTE: I don't believe this question is a duplicate of the one linked above, as I explain in the UPDATE below.]

Is there any way to define/instantiate a generic class using reflection?

So I have a bunch of classes, each of which owns an instance of a generic class that shares the type of its owner:

public class GenericClass<T>
{
    T Owner { get; set; }
    public GenericClass(T owner) { Owner = owner; }
}
public class MyClass
{
    private GenericClass<MyClass> myGenericObject;
    public MyClass() { myGenericObject = new GenericClass<MyClass>(this); }
}

This works, but of course I have to explicitly specify "MyClass" as the argument in the GenericClass definition. I'd like to be able to do something like this:

private GenericClass<typeof(this)> myGenericObject; // Error: invalid token

Is there anyway to dynamically specify the type of the generic object at compile time, based on the containing class?


UPDATE: After reading the answers from these questions, I learned that I could instantiate a local variable like so:

var myGenericObject = Activator.CreateInstance(typeof(GenericClass<>).MakeGenericType(this.GetType()));

but, of course, the this keyword is only available inside a method (so, for example, I could put this line of code in the constructor of MyClass). But I cannot use this approach to define an instance variable (i.e., myGenericObject, in the code above). Is there any way to specify a generic instance variable dynamically?

Community
  • 1
  • 1
kmote
  • 16,095
  • 11
  • 68
  • 91

3 Answers3

2

Regarding your update, you can pass any Type to MakeGenericType. For example, the following also works:

var myObject = new MyClass();

var myGenericObject = Activator.CreateInstance(typeof(GenericClass<>).MakeGenericType(typeof(MyClass)), myObject);

Console.WriteLine(myGenericObject.GetType());

Outputs:

ConsoleApplication1.GenericClass`1[ConsoleApplication1.MyClass]

myObject.GetType() also does the same thing:

var myGenericObject = Activator.CreateInstance(typeof(GenericClass<>).MakeGenericType(myObject.GetType()), myObject);
Cirdec
  • 24,019
  • 2
  • 50
  • 100
  • Thank you, but the point is I don't want to have to explicitly specify the Type. I want it specified dynamically at compile time. – kmote Sep 24 '13 at 19:34
  • What on earth does "dynamically at compile time" mean? Do you mean you just want to get rid of the <> from your syntax when writing programs? In that case make a static factory `public static GenericClass { public Create(T owner) { return new GenericClass(owner); } }` then you can call `GenericClass.Create(myObject)` and the compiler will infer the type. – Cirdec Sep 25 '13 at 04:10
  • 1
    Or do you really just mean "I want to make a GenericClass where the type argument is the type of it's owner", in which case you could write `public static GenericClass { public object Create(object owner) { return Activator.CreateInstance(typeof(GenericClass<>).MakeGenericType(object.GetType()), object); } }` then you can write `object myObject = new MyClass(); object gc = GenericClass.Create(object)` and be confident that `gc.GetType() == typeof(GenericClass)` even though the compiler forgot everything about `myObject` except for the fact it's an `object`. – Cirdec Sep 25 '13 at 04:14
  • (You're right that my "dynamic/compile time" comment was very poorly worded. Sorry for the confusion.) Your second comment is really getting at what I was searching for. You had a couple typos so it didn't compile at first, but essentially that's the solution I was looking for. Now the only question is: do I lose out in terms of type-safety by declaring `gc` as an `Object` rather than a `GenericClass`? Thanks for the help! – kmote Sep 25 '13 at 15:19
0

There is static built in construct for that:

Activator.CreateInstance()

Look at the overloads.

UPDATE

public Type FakeType { get; private set; }
public T CreateInstance<T>() where T : SomeEntityBase
{
     return (T) Activator.CreateInstance(FakeType);
}
Alex Denysenko
  • 134
  • 1
  • 4
  • 1
    Just want to point out that there is also a generic version: Activator.CreateInstance http://msdn.microsoft.com/de-de/library/0hcyx2kd.aspx – Boas Enkler Sep 24 '13 at 18:27
  • I did already =)) look at the comments to the question – Alex Denysenko Sep 24 '13 at 18:28
  • I'm having a hard time understanding how to use the generic version of CreateInstance, as the sample code in the [documentation](http://msdn.microsoft.com/en-us/library/0hcyx2kd.aspx) doesn't actually use the construct. – kmote Sep 24 '13 at 19:55
  • I updated the answer. Is it what you are looking for? – Alex Denysenko Sep 24 '13 at 20:29
0

Not sure if that is what are you looking for but can try with inheritance:

public class GenericClass<T>
{
    T Owner { get; set; }

    public GenericClass(T owner) { Owner = owner; }
}

public abstract class MyClassBase<T> where T : MyClassBase<T>
{
    protected GenericClass<T> MyGenericObject { get; private set; }

    protected MyClassBase() { MyGenericObject = new GenericClass<T>((T)this); }
}

public class MyClass1 : MyClassBase<MyClass1>
{
    public MyClass1() { }
}

public class MyClass2 : MyClassBase<MyClass2>
{
    public MyClass2() { }
}
Alessandro D'Andria
  • 8,663
  • 2
  • 36
  • 32
  • interesting approach, but it doesn't seem to get around the need to specify the `Type` argument (in your case, to `: MyClassBase`), whereas I was looking for a way to do so dynamically. – kmote Sep 24 '13 at 19:38