C# 泛型静态类-在运行时检索对象类型
我有一个X类型的对象,我可以(显然)在运行时检索它C# 泛型静态类-在运行时检索对象类型,c#,generics,reflection,static,C#,Generics,Reflection,Static,我有一个X类型的对象,我可以(显然)在运行时检索它 var type = myObject.GetType(); 我有一个通用的静态类 public static class MyStaticClass<T> { public static void DoStuff(T something) { // bla bla } } 公共静态类MyStaticClass { 公共静态真空度(T某物) { //布拉布拉 } } 我想做的是: MyS
var type = myObject.GetType();
我有一个通用的静态类
public static class MyStaticClass<T>
{
public static void DoStuff(T something)
{
// bla bla
}
}
公共静态类MyStaticClass
{
公共静态真空度(T某物)
{
//布拉布拉
}
}
我想做的是:
MyStaticClass<myObject.GetType()>.DoStuff(myObject);
MyStaticClass.DoStuff(myObject);
但我不能
事实上,MyStaticClass只在少数几个类型上运行,它们共享几个接口。解决方法之一是编写:
if (myObject.GetType() == typeof(X))
{
MyStaticClass<X>.DoStuff(myObject as X);
}
if (myObject.GetType() == typeof(Y))
{
MyStaticClass<Y>.DoStuff(myObject as Y);
}
if(myObject.GetType()==typeof(X))
{
MyStaticClass.DoStuff(myObject为X);
}
if(myObject.GetType()==typeof(Y))
{
MyStaticClass.DoStuff(myObject为Y);
}
但这是冗长的,写的到处都是丑陋的——我觉得我不应该这么做,但我也不应该这么做
我不敢相信没有解决办法。或者至少有更整洁的解决办法?还是我的方法一开始就错了(如果是这样的话,还有什么选择)?我是否应该为X、Y、Z创建一些(抽象?)基类?您可以使用反射,使用
Type.MakeGenericType
——但是您还需要使用反射来调用该方法。不过这有点痛苦
如果您使用的是C#4,您可以使用动态类型和类型推断-尽管这只适用于泛型方法而不是泛型类型,因此您需要使用:
public void DoStuffDynamic(dynamic item)
{
DoStuffHelper(item);
}
private static void DoStuffHelper<T>(T item)
{
MyClass<T>.DoStuff(item);
}
public void DoStuffDynamic(动态项)
{
Dostuff助手(项目);
}
专用静态无效DoStuffHelper(T项)
{
MyClass.DoStuff(项目);
}
编辑:为了提高性能,可以避免进行过多的实际反射。您可以对每个项目类型执行一次反射,创建一个形式为Action
的委托,并将其缓存在字典中。这可能比在每次执行时执行反射快得多
下面是一个简短但完整的示例:
using System;
using System.Collections.Generic;
using System.Reflection;
public static class MyStaticClass
{
private static readonly object mapLock = new object();
private static readonly Dictionary<Type, Action<object>>
typeActionMap = new Dictionary<Type, Action<object>>();
private static readonly MethodInfo helperMethod =
typeof(MyStaticClass).GetMethod("ActionHelper",
BindingFlags.Static |
BindingFlags.NonPublic);
public static void DoStuffDynamic(object item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
Type type = item.GetType();
Action<object> action;
lock (mapLock)
{
if (!typeActionMap.TryGetValue(type, out action))
{
action = BuildAction(type);
typeActionMap[type] = action;
}
}
action(item);
}
private static Action<object> BuildAction(Type type)
{
MethodInfo generic = helperMethod.MakeGenericMethod(type);
Delegate d = Delegate.CreateDelegate(typeof(Action<object>),
generic);
return (Action<object>) d;
}
private static void ActionHelper<T>(object item)
{
MyStaticClass<T>.DoStuff((T) item);
}
}
public static class MyStaticClass<T>
{
public static void DoStuff(T something)
{
Console.WriteLine("DoStuff in MyStaticClass<{0}>",
typeof(T));
}
}
public class Test
{
static void Main()
{
MyStaticClass.DoStuffDynamic("Hello");
MyStaticClass.DoStuffDynamic(10);
}
}
使用系统;
使用System.Collections.Generic;
运用系统反思;
公共静态类MyStaticClass
{
私有静态只读对象映射锁=新对象();
专用静态只读字典
typeActionMap=新字典();
私有静态只读MethodInfo helperMethod=
typeof(MyStaticClass).GetMethod(“ActionHelper”,
BindingFlags.Static|
BindingFlags(非公开);
公共静态void DoStuffDynamic(对象项)
{
如果(项==null)
{
抛出新的异常(“项”);
}
Type Type=item.GetType();
行动;
锁(映射锁)
{
if(!typeActionMap.TryGetValue(type,out action))
{
action=BuildAction(类型);
typeActionMap[type]=动作;
}
}
行动(项目);
}
私有静态操作BuildAction(类型)
{
MethodInfo generic=helperMethod.MakeGenericMethod(类型);
Delegate d=Delegate.CreateDelegate(typeof(Action)),
通用);
返回(动作)d;
}
私有静态void ActionHelper(对象项)
{
MyStaticClass.DoStuff((T)项);
}
}
公共静态类MyStaticClass
{
公共静态真空度(T某物)
{
Console.WriteLine(“MyStaticClass中的DoStuff”,
(T)型;
}
}
公开课考试
{
静态void Main()
{
MyStaticClass.DoStuffDynamic(“你好”);
MyStaticClass.DoStuffDynamic(10);
}
}
我只在必要的时候才使用这种类型的东西,但有时真的没有任何合理的选择。如果没有反射,这是不可能的,泛型类型参数必须在编译时知道。即使反思是可能的,我也不建议这样做。您应该更改您的设计。事实上,MyStaticClass只会在几种类型上运行,它们共享多个接口。一种解决方法是编写:
因此,您不能针对共享的
接口编写DoStuff
方法吗?这样,您就可以针对已知接口编程,而不是试图猜测对象的类型。整个方法似乎有点狡猾。然后您可以完全删除泛型。主要缺点是什么?这是性能问题吗?我知道反射往往很慢,速度相当慢,而且会失去任何编译时支持。有些情况下这是合适的,但是,我认为你的设计有缺陷。我在.NET3.5上。我想我也可以创建一个非泛型的MyStaticClass
,它的DoStuff(object myObject)
方法将包含所有那些讨厌的“如果那是一个x,就在它上面调用MyStaticClass.DoStuff。如果那是一个y…”,这样至少它们不会到处都是。@Vibo:是的,集中化肯定会有帮助。然后你可以在那个地方使用反射。如果您想缓解反射的性能问题,如果您感兴趣,可以通过一些方法来解决。@Vibo:我提供了一个完整的示例。太棒了!非常感谢您,X
,Y
和Z
共享一些通用接口(例如IHavingID
,确保它们都有ID
属性),但是MyStaticClass
保留了一个Ts字典,我需要一些单独的Xs、Ys和Zs字典,在DoStuff
内部创建一个名为IWhatever
的接口。那就让你的字典只包含IWhatever的条目。这样,您可以以相同的方式处理所有列表?这里需要一个公共接口/基类。