3

I need to create Dynamic T using interface. But I am getting "Type Casting" error. Here is my code :

interface IEditor { }

class Editor : IEditor { }

class Test<T> { }

Now the will be dynamic so I am using this code below :

Test<IEditor> lstTest = (Test<IEditor>)Activator.CreateInstance(typeof(Test<>).MakeGenericType(typeof(Editor)));

I am getting following error

Unable to cast object of type 'CSharp_T.Test`1[CSharp_T.Editor]' to type 'CSharp_T.Test`1[CSharp_T.IEditor]'.

This error is not compilation error but I am getting run time error.

millimoose
  • 39,073
  • 9
  • 82
  • 134
Debajit Mukhopadhyay
  • 4,072
  • 1
  • 17
  • 22
  • 3
    I dunno if "dynamic" is the best name for your question, because it may be confused with the dynamic keyword, which has nothing to do with this. P.S. This looks wrong typeof(Test<>) You didn't include a type in the brackets? – Alan Sep 20 '13 at 20:04
  • Is the interface and class really empty? – Bit Sep 20 '13 at 20:05
  • The error message seems incomplete. – millimoose Sep 20 '13 at 20:06
  • I am not getting compilation error but i am getting run time error – Debajit Mukhopadhyay Sep 20 '13 at 20:06
  • 5
    Also I believe the reason for the error is that a `Test` isn't a subtype of `Test`, and thus you can't cast the former to the latter. This has nothing to do with your use of `Activator`, even `(Test) new Test()` would fail. The explanation for this can probably be found on Stack Overflow in hundreds of variants. – millimoose Sep 20 '13 at 20:07
  • @Alan is correct typeof(IEditor) or typeOf(Editor) maybe. – Bit Sep 20 '13 at 20:07
  • 2
    @Alan `typeof(Test<>)` is perfectly valid, it's a way to get a reference to the generic type without parameters. – millimoose Sep 20 '13 at 20:09
  • One of my answers about the reason why that relationship between types isn't there, explained with `List`s: http://stackoverflow.com/questions/17952546/polymorphic-type-parameters-in-generic-collections/17952762#17952762 – millimoose Sep 20 '13 at 20:10
  • Thanks @millimoose for your inputs. But how can I cast (Test) new Test() ? Is there any way ? – Debajit Mukhopadhyay Sep 20 '13 at 20:11
  • @DebajitMukherjee You can't as they stand. The types are not compatible. It would be in violation of a fundamental principle the type system is based on. You'd need to introduce a new `interface ITest` and use that, but then you'd have the restriction that `TEditor` can only be used as the return type of a method. (Or maybe an `out` parameter as well, I don't know this by heart.) – millimoose Sep 20 '13 at 20:15
  • @Alan Seems the correct terms for what I mean on MSDN is *generic type definition* (e.g. `Dictionary<,>`) and *constructed generic type* (e.g. `Dictionary`): http://msdn.microsoft.com/en-us/library/ms172192.aspx – millimoose Sep 20 '13 at 20:23
  • While `typeof(Test<>).MakeGenericType(typeof(Editor))` is correct and works correctly, in this case, where both `Type` objects are "constants", it is much easier to write simply `typeof(Test)`. – Jeppe Stig Nielsen Sep 20 '13 at 21:40
  • Also, you don't show any of the constructors, so we can't see why you can't just use `new Test()` instead of the `Activator` stuff. Are there any cases where the `new` expression will fail while this specific overload of `CreateInstance` works? – Jeppe Stig Nielsen Sep 20 '13 at 21:45

2 Answers2

6

Generic classes do not support covariance, but interfaces do. If you define an interface ITest<> and mark T as an out parameter, like this,

interface IEditor { }

class Editor : IEditor { }

interface ITest<out T> { }

class Test<T> : ITest<T> { }

you will be able to do this:

ITest<IEditor> lstTest = (ITest<IEditor>)Activator
    .CreateInstance(typeof(Test<>)
    .MakeGenericType(typeof(Editor)));

However, this would limit the ways in which the T parameter could be used inside ITest<> and its implementations.

Demo on ideone.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1

Test is not covariant (it is invariant in it's generic argument). Because of this a Test<IEditor> is not a subtype of a Test<IEditor>. There is no relationship between those two types.

You can create an object of type Test<IEditor> to begin with, instead of a Test<IEditor>, and then the cast can succeed.

Servy
  • 202,030
  • 26
  • 332
  • 449