使用来自System.Type的泛型类型调用泛型方法
本文关键字:泛型类型 调用 泛型方法 Type System | 更新日期: 2023-09-27 18:16:23
下面是一个代码示例和问题,请注意我不能使用c# 4.0和动态关键字。
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!";
}
}
}
我还尝试了一些使用Delegate的更多方法。CreateDelegate但是没有任何运气。这有可能吗?
编辑:我不怕使用动态方法(和MSIL汇编器),但我在这方面的知识非常有限。
编辑2:这里有一个更接近我真正想做的例子:
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).
}
}
你的评论看起来你已经知道怎么做了:
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];
这实际上只是把你的注释变成了代码。那是不是不符合你的要求?
在我看来,主要的问题是,你想做什么?
如果你只是想把一个字符串赋值给一个引用对象,你可以这样做:
泛型可以在运行时定义,但这不是很舒服,必须通过反射来完成…在我看来,这是一个"不去",但只是一个意见
尝试使用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!";
}
}
}
更新3:好吧,既然你对一个丑陋的解决方案很满意,你可能想检查未记录的__refvalue
和__makeref
关键字。
似乎您的问题是您希望能够指定ref object
参数的类型为转换为或更改为。
这样做的问题是,您不能随意地将任何类型的T
变量赋值给string
,例如。所以你需要传入一个ref object
或ref string
来工作。
在我看来,就像oberfreak确定了您试图实现的目标(我最初没有注意到您已将o
初始化为string
,因此显然希望其实际类型影响Test2
函数的行为)。他的回答正好适合你。
Update:你在评论中提到你想要做的是使用字典可以实现的动态行为。我猜是这样的吧?
更新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);
}
}
这个应该可以工作。但你不能真正实现同样的事情与泛型,因为没有办法做到这一点(如你所知):
// not allowed
// |
// -----------
// | |
TypeHandler<o.GetType()>.Process(ref o);
如果存在,那么一切都准备好了。但是唯一可行的方法是使用反射,对于这样的事情来说,这是丑陋和昂贵的,并且显然会违背保持简单和确保良好性能的意图。
实现方法Test2的正确方法是
static public void Test2<T>(ref T s)
{
if (s is string)
{
s = (T)(Object)"Hello world!";
}
}
还是我遗漏了什么?
如果你可以将ref
更改为常规返回,你可以在4.0中通过dynamic
大规模作弊:
dynamic foo = obj;
Test(foo);
Test<TheActualTypeOfObj>(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;
}
上面写着"Hello world!"