C# 从System.type使用泛型类型调用泛型方法

C# 从System.type使用泛型类型调用泛型方法,c#,.net,generics,reflection,byref,C#,.net,Generics,Reflection,Byref,下面是一个代码示例和问题,请注意,我不能使用C#4.0和dynamic关键字 static class TestClass { static void Main(string[] args) { Object o = "Previous value"; Test(ref o); Trace.WriteLine(o); } static public void Test<T>(ref T obj)

下面是一个代码示例和问题,请注意,我不能使用C#4.0和dynamic关键字

static class TestClass
{
    static void Main(string[] args)
    {
        Object o = "Previous value";
        Test(ref o);
        Trace.WriteLine(o);
    }

    static public void Test<T>(ref T obj)
    {
        //  The goal is to somehow invoke Test2 with the real type of obj, i.e the type in obj.GetType() 

        //  1st try:
        Test2(ref obj); // This doesn't work because the type in Test2 will be the same as T here.

        //  2nd try:
        MethodInfo mi = typeof(TestClass).GetMethod("Test2");
        mi = mi.MakeGenericMethod(new Type[] { obj.GetType() });
        mi.Invoke(null, new Object[] { obj }); // obj is no longer by reference so we need to store the object array and copy back the result after the call

        //  3rd try, successful implementation by the smartest mind of stack overflow :)
    }

    static public void Test2<T>(ref T s)
    {
        if (typeof(T) == typeof(String))
        {
            s = (T)(Object)"Hello world!";
        }
    }
}
静态类TestClass
{
静态void Main(字符串[]参数)
{
对象o=“以前的值”;
试验(参考o);
微量写线(o);
}
静态公共空隙试验(参考T obj)
{
//目标是以某种方式使用实际类型的obj调用Test2,即obj.GetType()中的类型
//第一次尝试:
Test2(ref obj);//这不起作用,因为Test2中的类型与这里的t相同。
//第二次尝试:
MethodInfo mi=typeof(TestClass).GetMethod(“Test2”);
mi=mi.MakeGenericMethod(新类型[]{obj.GetType()});
Invoke(null,new Object[]{obj});//obj不再是通过引用的,因此我们需要存储对象数组,并在调用后复制回结果
//第三次尝试,由最聪明的堆栈溢出思想成功实施:)
}
静态公共无效测试2(参考T s)
{
if(typeof(T)=typeof(String))
{
s=(T)(对象)“你好,世界!”;
}
}
}
我还尝试了更多使用Delegate.CreateDelegate的方法,但没有成功。 这有可能吗

编辑:我不怕使用动态方法(和MSIL汇编程序),但我在这方面的知识非常有限

Edit2:这里有一个更接近我真正想要做的例子:

public static class TypeHandler<T>
{
    public delegate void ProcessDelegate(ref T value);

    public static readonly ProcessDelegate Process = Init();

    private static ProcessDelegate Init()
    {
        //  Do lot's of magic stuff and returns a suitable delegate depending on the type
        return null;
    }
}


static class TestClass
{
    static public void Main(string[] args)
    {
        Object o = "Previous value";
        Test(ref o);
        Trace.WriteLine(o);
    }

    static public void Test<T>(ref T obj)
    {
        if (obj is T)
        {
        //  Optimized, common case
            TypeHandler<T>.Process(ref obj);
            return;
        }
        Type t = obj.GetType();
        //  How to call the delegate found in TypeHandler<t>.Process ? (I can get delegate but I can't call it).


    }

}
公共静态类TypeHandler
{
公共委托无效处理委托(参考T值);
公共静态只读ProcessDelegate进程=Init();
私有静态ProcessDelegate Init()
{
//做很多神奇的事情,并根据类型返回一个合适的委托
返回null;
}
}
静态类TestClass
{
静态公共void Main(字符串[]args)
{
对象o=“以前的值”;
试验(参考o);
微量写线(o);
}
静态公共空隙试验(参考T obj)
{
if(obj是T)
{
//优化,常见情况
TypeHandler.Process(参考obj);
返回;
}
类型t=obj.GetType();
//如何调用TypeHandler.Process中的委托?(我可以获取委托,但无法调用它)。
}
}

在我看来,主要的问题是,你想做什么

如果只想将字符串指定给引用对象,可以尝试以下操作:

泛型可以在运行时定义,但它不是很舒服,必须通过反射来完成。。。在我看来,这是一个“不可能”,但只是一个机会

尝试使用
object.GetType()
获取对象的当前类型

static class TestClass {
    static void Main(string[] args) {
        Object o = "Previous value";
        Test(ref o);
        Console.WriteLine(o);
        Console.ReadLine();
    }

    static public void Test<T>(ref T obj) {
        Object o = (Object)obj;
        Test2(ref o);
        obj = (T)o;
    }

    static public void Test2(ref object s) {
        if (s.GetType().Equals(typeof(String))) {
            s = "Hello world!";
        }
    }
}
静态类TestClass{
静态void Main(字符串[]参数){
对象o=“以前的值”;
试验(参考o);
控制台写入线(o);
Console.ReadLine();
}
静态公共空隙试验(参考T obj){
对象o=(对象)obj;
试验2(参考文献o);
obj=(T)o;
}
静态公共void Test2(ref对象s){
如果(s.GetType().Equals(typeof(String))){
s=“你好,世界!”;
}
}
}

您的评论看起来您已经理解了如何操作:

MethodInfo mi = typeof(TestClass).GetMethod("Test2");
mi = mi.MakeGenericMethod(new Type[] { obj.GetType() });
object[] args = new object[] { obj };
mi.Invoke(null, args);
obj = (T) args[0];

这实际上只是将您的注释转换为代码。这是否不符合您的要求?

更新3:好的,既然您对一个难看的解决方案很满意,那么您可能需要退出


您的问题似乎是希望能够指定要转换或更改为的
ref对象
参数的类型

问题在于,例如,不能将任何类型的变量
t
任意分配给
字符串。因此,您需要传入一个
ref对象
ref字符串
,才能使其正常工作

在我看来,它似乎已经确定了您试图实现的目标(我最初没有注意到您已将
o
初始化为
字符串
,因此显然希望其实际类型影响
Test2
函数的行为)。他的回答适合你

更新:您在评论中提到,您尝试的是使用字典实现的动态行为。我猜是这样的吧

更新2:根据更新的示例更新了此示例

public static class TypeHandler // note: get rid of generic T parameter
{
    delegate void ProcessDelegate(ref object obj); // again, not generic

    static Dictionary<Type, ProcessDelegate> processors = new Dictionary<Type, ProcessDelegate>()
    {
        { typeof(string), (ref object obj) => { obj = "Hello, world!"; } }
        // etc.
    };

    public static void Process(ref object obj)
    {
        processors[obj.GetType()].Invoke(ref obj);
    }
}
公共静态类TypeHandler//注意:去掉泛型T参数
{
delegate void ProcessDelegate(ref object obj);//同样,不是泛型
静态字典处理器=新字典()
{
{typeof(string),(ref object obj)=>{obj=“你好,世界!”;}
//等等。
};
公共静态作废流程(参考对象obj)
{
处理器[obj.GetType()].Invoke(ref-obj);
}
}
这应该行得通。但是你不能用泛型实现同样的效果,因为没有办法做到这一点(你知道):

//不允许
//               |
//          -----------
//         |           |
TypeHandler.Process(参考o);

如果有,那你就准备好了。但唯一可能的方法是使用反射,这对于类似的东西来说既丑陋又昂贵,显然会挫败您保持这种简单并确保良好性能的意图。

实现方法Test2的正确方法是

static public void Test2<T>(ref T s)
    {
        if (s is string)
        {
            s = (T)(Object)"Hello world!";
        }
}
静态公共无效测试2(参考T s)
{
如果(s是字符串)
{
s=(T)(对象)“你好,世界!”;
}
}

还是我遗漏了什么?

如果您可以将
ref
更改为常规返回,您可以通过
dynamic
在4.0中大量作弊:

dynamic foo = obj;
Test(foo);
现在是:

Test<TheActualTypeOfObj>(obj);
测试(obj);
完整示例:

static void Main(string[] args)
{
    object o = "Previous value";
    o = Test2((dynamic)o);
    Trace.WriteLine(o);
}

static public T Test2<T>(T s)
{
    if (typeof(T) == typeof(string))
    {
        s = (T)(object)"Hello world!";
    }
    return s;
}
static void Main(字符串[]args)
{
对象o=“以前的值”;
o=测试2((动态)o);
微量写线(o);
}
静态公共测试2(TS)
{
static void Main(string[] args)
{
    object o = "Previous value";
    o = Test2((dynamic)o);
    Trace.WriteLine(o);
}

static public T Test2<T>(T s)
{
    if (typeof(T) == typeof(string))
    {
        s = (T)(object)"Hello world!";
    }
    return s;
}