在运行时设置泛型类型

时间:2010-04-09 02:24:37

标签: c# generics

我有一个班级

public class A<T>
{
   public static string B(T obj)
   {
       return TransformThisObjectToAString(obj);
   }
}

上面使用字符串纯粹是示范性的。我可以在已知/指定的类型上调用这样的静态函数:

string s= A<KnownType>.B(objectOfKnownType);

如果我事先不知道 T ,我该怎么做这个电话,而是我有一个类型为 Type 的变量。如果我这样做:

Type t= typeof(string);
string s= A<t>.B(someStringObject);

我收到此编译器错误:

Cannot implicitly convert type 't' to 'object'

6 个答案:

答案 0 :(得分:26)

您无法直接执行此操作,但可以使用反射在运行时提供类的类型参数。我没有测试过这个,但是这样的事情应该有效:

// We want to do something like this:
//    object o = "Hello"
//    Type t = o.GetType(); 
//
// This is pseudo-code only:
//    string s = A<t>.B(o); 

string InvokeA(object o) {
  // Specify the type parameter of the A<> type
  Type genericType = typeof(A<>).MakeGenericType(new Type[] { o.GetType() });
  // Get the 'B' method and invoke it:
  object res = genericType.GetMethod("B").Invoke(new object[] { o });
  // Convert the result to string & return it
  return (string)res;
}

当然,问题是这是否真的是你需要的 - 如果你对作为参数给出的对象一无所知,你也可以用对象编写整个代码。但是,我可以想象一些有用的场景,所以我想你可以尝试使用它。

答案 1 :(得分:11)

你做不到。必须在编译时知道泛型类型标识符。

修改

从其他帖子开始,似乎可以通过动态生成方法并调用它 - 当然这有危险。有关更多信息,请参阅Thomas'和Dathan的帖子。

答案 2 :(得分:9)

在框架和CLR中绝对支持这一点 - 只是在C#中不优雅。但是,在辅助方法的帮助下,你可以完成我认为你想要的东西:

public class A<T>
{
    public static string B(T obj)
    {
        return obj.ToString();
    }
}

public class MyClass
{
    public static void DoExample()
    {
        Console.WriteLine(ExecuteB("Hi"));
        Console.WriteLine(ExecuteB(DateTime.Now));
    }

    public static object ExecuteB(object arg)
    {
        Type arg_type = arg.GetType();
        Type class_type = typeof(MyClass);
        MethodInfo mi = class_type.GetMethod("ExecuteBGeneric", BindingFlags.Static | BindingFlags.Public);
        MethodInfo mi2 = mi.MakeGenericMethod(new Type[] { arg_type });
        return mi2.Invoke(null, new object[] { arg });
    }

    public static object ExecuteBGeneric<T>(T arg)
    {
        return A<T>.B(arg);
    }

答案 3 :(得分:1)

你做不到。但是你提出的问题是错误的问题。在这种情况下(如99%的情况),您实际需要的只是类型约束

尝试:

public class A<T> where T : object

或者,如果T是已知类,子类或接口,那么最好使用

public class A<T> where T : YourAbstractClass

还存在其他类型约束。更多详情:http://msdn.microsoft.com/en-us/library/d5x73970(VS.80).aspx

总的来说,在学习一门新语言时,你经常需要广泛地思考你想要实现的内容,而不是专门找到你想要做什么的内容。这很像现实世界的口头语言。通过阅读字典学习德语并将单词强制用于英语语法,或者学习语法并学习单词来学习德语之间的区别。是的,一个德语发言者会理解一个在词典中发言的人,但每个句子的WTF会更高。

答案 4 :(得分:0)

尝试在运行时替换type参数会破坏类型saftey的整个目的,这是由C#compiler强制执行的.C#编译器确保在编译时指定了类型参数,并且在运行时类型参数没有歧义。怀疑你可以在Generic Type中运行时替换类型参数。类型为“ Type ”的类型参数类似于具有未绑定的泛型类型。

答案 5 :(得分:0)

我根据这里的一些答案创建了这个帮助方法,而不是在网络上。

用法:

var unzipExtractor = unzip.Extract({ path: dir });
var source = fs.createReadStream(dir + 'sub.zip');
var unZip = source.pipe(unzipExtractor);
unZip.on('error', function(err) {
   fs.unlink(dir + 'sub.zip', function(err){
       if (err) console.log(err); else console.log('File extracted !');
   })
})

方法:

InvokeGenericMethodWithRuntimeGenericArguments( MyMethodWithGenericType<IType>, new[] {MyRuntimeGenericType}, null);