C#在运行时传递泛型参数类型

时间:2012-12-23 16:02:15

标签: c# generics types interface linked-list

在我的应用程序中,我有使用输入和输出相互链接的组件。将要交换的数据可以是任何类型,因此我使用泛型。

public interface IInputVariable<T>
{
    IOutputVariable<T> Source { get; set; }
}


public interface IOutputVariable<T>
{
    T Value { get; set; }
}

在另一个类中,组件链接在一起。链接了哪些组件,是从文件派生的。进行链接的类不知道输入和输出交换的类型。这个类只想用以下代码连接它们:

IOutputVariable<double> output;
Type argumentType = output.GetType().GetGenericArguments()[0];
IInputVariable<argumentType> input = new BasicInputVariable<argumentType>();
input.Source = output;

此代码无法编译,因为argumentType不能用作通用参数。有没有正确的方法来制定这个?或者是否可以在不知道其参数类型的情况下声明泛型变量?

2 个答案:

答案 0 :(得分:2)

设置Source属性的最简单方法是在BasicInputVariable<T>中创建带有IOutputVariable<T>的counstructor:

public BasicInputVariable(IOutputVariable<T> source)
{
    Source = source;
}

然后您可以轻松实例化它:

IOutputVariable<double> output;
Type argumentType = output.GetType().GetGenericArguments()[0];
object input = Activator.CreateInstance(typeof(BasicInputVariable<>)
                                       .MakeGenericType(argumentType), output);

另一种方法是创建并实现一个可以提供Source属性的接口:

public interface ISetSource
{
    object Source { get; set; }
}

public class BasicInputVariable<T> : IInputVariable<T>, ISetSource
{
    public IOutputVariable<T> Source { get; set; }

    object ISetSource.Source
    {
        get { return Source; }
        set { Source = (IOutputVariable<T>) value; }
    }
}

现在您可以访问Source属性:

IOutputVariable<double> output;
var input = (ISetSource) Activator.CreateInstance(typeof (BasicInputVariable<>)
                                                 .MakeGenericType(argumentType));
input.Source = output;

使用输入/输出泛型参数可能更加类型安全,但不幸的是我们不能将它们与值类型一起使用...

答案 1 :(得分:0)

警告:这真是丑陋的黑客,不推荐..

如果你有.NET 4.0:

IOutputVariable<double> output = something;
dynamic input = Activator
                .CreateInstance(typeof(BasicInputVariable<>)
                                .MakeGenericType(output
                                                 .GetType()
                                                 .GetGenericArguments()[0]));
//or may be:
//dynamic input = typeof(BasicInputVariable<>)
//                .MakeGenericType(output
//                                 .GetType()
//                                 .GetGenericArguments()[0])
//                .GetConstructor(new Type[0])
//                .Invoke(new object[0]);

input.Source = output;

但是我不明白是什么阻止你将类型参数double本身直接传递给你的BasicInputVariable构造函数?

IOutputVariable<double> output = something;
IInputVariable<double> input = new BasicInputVariable<double>();
input.Source = output;

如果类型参数可以是任何东西,那么为什么不使整个方法通用?可能是:

void Method<T>()
{
    IOutputVariable<T> output = something;
    IInputVariable<T> input = new BasicInputVariable<T>();
    input.Source = output;
}

这是有效的,因为输入和输出变量的T相同..


很难在没有更多细节的情况下考虑更好的解决方案,但认真的是你应该首先重新考虑你的设计。