2

I have simplified the code but basically this code runs on a loop and the types come from reflection. The only constant here is the IWorker<T> interface.

I need to access the properties of the IWorker but I can't cast it as the argType is not accepted by the compiler, any ideas?

(I could do this with dynamic but I was hoping for an alternative to prevent future bugs due to refactoring)

Type argType = @interface.GetGenericArguments().First();

var worker = (IWorker<argType>)FormatterServices.GetUninitializedObject(MyType);

MyType derives from IWorker<T> where T is unknown at compile time.

nawfal
  • 70,104
  • 56
  • 326
  • 368
Pete
  • 73
  • 5
  • Covert.ChangeType + MakeGenericType will help you. – It'sNotALie. Jun 12 '13 at 18:15
  • 1
    Is it possible to make this method generic and cast the object to `IWorker` instead of passing in a `Type` argument? That's the only way you can maintain compile time type safety. If you can't, then whatever you do loses static typing. – Servy Jun 12 '13 at 18:16
  • MakeGenericType returns a type which means I would be in the same situation. I want to be able to compile code like worker.MyProperty = "Somwthing"; – Pete Jun 12 '13 at 18:18
  • @Servy what method do you mean? the FormatterServices.GetUninitializedObject creates an instance, its a .net method and it differs from ACtivator.CreateInstance in that it does not call constructor, I cant touch it. I'm trying to cast the result which is an object to maintain type safety. I tried (IWorker) and (IWorker) to no avail – Pete Jun 12 '13 at 18:20
  • @Pete That method isn't really relevant at all. The question is whether you can "choose" the type to be used through a generic argument instead of a `Type` object. You can get a `Type` object from a generic argument, but not the other way around. Since you seem to have not considered it I'll just post it as an answer. – Servy Jun 12 '13 at 18:22
  • @Servy I tries to simply the code for better understanding but may have made it more confusing. The line Type argType = typeof(ArgType); is in fact something like: Type argType = @interface.GetGenericArguments().First(); – Pete Jun 12 '13 at 18:26
  • more directly related: http://stackoverflow.com/questions/2078914/c-sharp-dynamic-generic-type – nawfal Jun 12 '13 at 20:28

2 Answers2

2

If at all possible you should make the method generic. It is the only way that you can maintain compile time type safety. If this isn't an option, and this method must accept a Type parameter directly then whatever solution you end up using will, by definition, not be able to maintain static typing.

public static IWorker<T> Foo<T>()
{
    return (IWorker<T>)FormatterServices.GetUninitializedObject(typeof(T));
}

You can then call it like:

IWorker<ArgType> worker = Foo<ArgType>();
nawfal
  • 70,104
  • 56
  • 326
  • 368
Servy
  • 202,030
  • 26
  • 332
  • 449
  • FormatterServices.GetUninitializedObject creates an instance of a type which derives from IWorker. T is unknown as it varies, I know T's type from @interface.GetGenericArguments().First(); I'm sorry if I don't see how this can help..? – Pete Jun 12 '13 at 18:30
  • @Pete That's why I asked how you were generating the `Type` object, and if it was possible to use a generic method instead. When you indicated you didn't know I posted this answer. It's possible that you really don't know the type at compile time at all, in which case there is no conceivable solution that will maintain static typing; you will need to use reflection (which is what `dynamic` effectively is a shortcut for if you want to use that) and code without the compiler's help. – Servy Jun 12 '13 at 18:32
  • argType is a variable of type Type. this does not compile: IWorker worker = Foo(); – Pete Jun 12 '13 at 18:32
  • @Pete see the edit.. and now the question is completely different, ahh :) – nawfal Jun 12 '13 at 18:33
  • Yeah I edited the question to make it more clear, previously that line was only edited in the comments, my bad... However, your edit does not reflect the fact that the argType is discovered through reflection, which is why it does not compile as p.s.w.g. says: Generic type parameters must be known at compile time – Pete Jun 12 '13 at 18:35
1

I'm afraid you can't do that. Generic type parameters must be known at compile time. Type-casts, too, must be known at compile time. There are pretty much two options:

  1. Use a generic method (see Servy's answer).

  2. Create a non-generic interface and make IWorker<T> inherit from it:

    public interface IWorker 
    { 
        string MyProperty { get; }
    }
    
    public interface IWorker<T> : IWorker
    {
        ...
    }
    

    Then you can use it like this:

    var worker = (IWorker)FormatterServices.GetUninitializedObject(MyType);
    worker.MyProperty = "Somwthing";
    
Community
  • 1
  • 1
p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
  • "Generic type parameters must be known at compile time. Type-casts, too" that's the key I missed out on my knowledge base, type casts as well. The only work around in this case is refactoring the IWorker as you examplified. option 1 is not an option i think as the argType is a variable and not a known type as compile time. – Pete Jun 12 '13 at 18:41