Charlotte Skardon
Charlotte Skardon

Reputation: 6270

Out generic parameters with types only known at runtime

I have an interface:

public interface IOut<T>
{
    void Get(out T output);
}

and a class that implements it:

public class Impl : IOut<string>, IOut<int>{
    public void Get(out string output) { output = "string"; }
    public void Get(out int output) { output = 12; }
}

I can do the following just fine:

public static void Main()
{
    dynamic dImpl = new Impl();

    string sOutput;
    int iOutput;

    dImpl.Get(out sOutput);
    dImpl.Get(out iOutput);

    Console.WriteLine(sOutput);
    Console.WriteLine(iOutput);
}

My problem is that I only know the type I need to get at runtime, so how I want to call my Get code is like so:

public static void Main()
{
    dynamic dImpl = new Impl();

    var t = typeof(string);
    t output;
    dImpl.Get(out output);

    Console.WriteLine(output);
}

Now, I know this won't work, and I've tried reflectively performing a Cast:

public static T Cast<T>(object o) { return (T) o; }

but I don't have an object to cast, I only have a Type. I've tried Defaults:

public static T Default<T>() { return default(T); }

but the default for things like string etc is null, and when invoking the method via reflection:

var method = typeof(Program).GetMethod("Default").MakeGenericMethod(typeof(string));
var defaulted = method.Invoke(null, null);

defaulted is going to be null, and when calling dImpl.Get(out defaulted) the runtime is unsure of which overload to use.

So, what I'm looking for is either: a) someway to do this using the current interface setup [preferred] b) a different way to achieve the goals

Upvotes: 0

Views: 136

Answers (2)

Lee
Lee

Reputation: 144136

You can get the method to invoke from the interface type instead of the implementing type:

object[] parameters = new object[] { null };
Type typeParam = typeof(string);
Type ifaceType = typeof(IOut<>).MakeGenericType(typeParam);
MethodInfo method = ifaceType.GetMethod("Get");

var impl = new Impl();
method.Invoke(impl, parameters);

object outParam = parameters[0];

Upvotes: 2

Nick Butler
Nick Butler

Reputation: 24383

If you don't know the type of output until runtime, you can't declare a strongly-typed instance of it in C#.

If you can make the calling logic ( Main in your example ) generic on T too, that would work - but this only defers your problem.

The other option is to declare output as a base class or interface and restrict the generic T to that. Using object as the base class might work for you - depends on what you want to do with it.

Upvotes: 0

Related Questions