C# 在运行时设置泛型类型

C# 在运行时设置泛型类型,c#,generics,C#,Generics,我有一节课 public class A<T> { public static string B(T obj) { return TransformThisObjectToAString(obj); } } 你不能。泛型类型标识符必须在编译时已知 编辑 与其他帖子一样,通过动态生成方法并调用它似乎是可能的——这当然有危险。有关更多信息,请参阅Thomas和Dathan的文章。试图在运行时替换类型参数将破坏类型安全的全部目的,这是由C#编译器强制执行的

我有一节课

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

你不能。泛型类型标识符必须在编译时已知

编辑


与其他帖子一样,通过动态生成方法并调用它似乎是可能的——这当然有危险。有关更多信息,请参阅Thomas和Dathan的文章。

试图在运行时替换类型参数将破坏类型安全的全部目的,这是由C#编译器强制执行的。C#编译器确保在编译时指定类型参数,并且在运行时类型参数没有歧义。我怀疑您是否可以在运行时将类型参数替换为泛型类型。指定类型为“type”的类型参数这几乎就像拥有一个未绑定的泛型类型。

您不能直接这样做,但可以使用反射在运行时提供类的类型参数。我还没有测试过这个,但类似的东西应该可以工作:

// 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;
}
//我们想这样做:
//对象o=“你好”
//类型t=o.GetType();
//
//这只是伪代码:
//字符串s=A.B(o);
字符串调用a(对象o){
//指定类型的类型参数
Type genericType=typeof(A).MakeGenericType(新类型[]{o.GetType()});
//获取并调用“B”方法:
object res=genericType.GetMethod(“B”).Invoke(新对象[]{o});
//将结果转换为字符串并返回它
返回(字符串)res;
}

当然,问题是这是否真的是您所需要的——如果您对作为参数给出的对象一无所知,那么您也可以只使用对象编写整个代码。但是,我可以想象在某些情况下这会很有用,所以我想您可以尝试使用它。

框架和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);
    }
公共A类
{
公共静态字符串B(T obj)
{
返回obj.ToString();
}
}
公共类MyClass
{
公共静态void DoExample()
{
Console.WriteLine(ExecuteB(“Hi”);
Console.WriteLine(ExecuteB(DateTime.Now));
}
公共静态对象ExecuteB(对象arg)
{
类型arg_Type=arg.GetType();
类型class_Type=typeof(MyClass);
MethodInfo mi=class_type.GetMethod(“ExecuteBGeneric”,BindingFlags.Static | BindingFlags.Public);
MethodInfo mi2=mi.MakeGenericMethod(新类型[]{arg_Type});
返回mi2.Invoke(null,新对象[]{arg});
}
公共静态对象ExecuteBGeneric(T参数)
{
返回A.B(arg);
}

您不能。但是您针对提供的案例提出了错误的问题。在这种情况下(与99%的案例一样),您实际需要的只是一个类型约束

尝试:

公共A类,其中T:object
或者,如果T是一个已知的类、子类或接口,那么最好使用

public class A<T> where T : YourAbstractClass
公共类A,其中T:YourAbstractClass
还存在其他类型约束。更多详细信息:


一般来说,在学习一门新语言时,你通常必须广泛地思考你想要达到的目标,而不是具体地找到你想要做的事情。这很像现实世界中的口头语言。这是通过阅读字典和将单词强制转换成英语语法来学习德语,或者学习语法和pi之间的区别把单词拼凑起来。是的,说德语的人会听懂别人在用字典说话,但每句话的WTF计数会高得多。

我根据这里的一些答案和网上的其他地方创建了这个帮助方法

用法:

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

我猜我误读了这个问题。除了你所说的之外,我真的无法添加任何其他内容。更准确的说法是,没有静态类型的方法;或者可能没有惯用的方法。但正如Tomas和我的回答所示,该方法可以动态解析,并在运行时使用任意参数调用。哦,我没有意识到你会这样做uld通行证
A
typeof()
。你的代码肯定比我的干净。干得好。我不太喜欢你能用C写
A
,因为它不是一种真正的类型。这是一种奇怪的事情。无论如何,我想它有时是有用的:-)。写
A
,以及类似
外部的东西。内部的
对于
类型的
参数很有用,但这是一件好事,在其他上下文中不允许使用它,因为您是对的,它不是C#类型。
a
是一个不完整的类型。我在工厂的上下文中使用过类似的构造,在工厂的上下文中,我使用CRTP查找从泛型库继承的类型。我将从程序集加载所有类型,看看是否可以加载对该类型的泛型基进行测试,然后查看该类型是否继承了实例化。如果继承了,则是我的工厂可以创建的类型之一。关闭
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);
    }
public class A<T> where T : object
public class A<T> where T : YourAbstractClass
InvokeGenericMethodWithRuntimeGenericArguments( MyMethodWithGenericType<IType>, new[] {MyRuntimeGenericType}, null);
public static object InvokeGenericMethodWithRuntimeGenericArguments(Action methodDelegate, Type[] runtimeGenericArguments, params object[] parameters)
        {
            if (parameters == null)
            {
                parameters = new object[0];
            }
            if (runtimeGenericArguments == null)
            {
                runtimeGenericArguments = new Type[0];
            }

            var myMethod = methodDelegate.Target.GetType()
                         .GetMethods()
                         .Where(m => m.Name == methodDelegate.Method.Name)
                         .Select(m => new
                         {
                             Method = m,
                             Params = m.GetParameters(),
                             Args = m.GetGenericArguments()
                         })
                         .Where(x => x.Params.Length == parameters.Length
                                     && x.Args.Length == runtimeGenericArguments.Length
                         )
                         .Select(x => x.Method)
                         .First().MakeGenericMethod(runtimeGenericArguments);
            return myMethod.Invoke(methodDelegate.Target, parameters);
        }