Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/271.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 泛型静态类-在运行时检索对象类型_C#_Generics_Reflection_Static - Fatal编程技术网

C# 泛型静态类-在运行时检索对象类型

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

我有一个X类型的对象,我可以(显然)在运行时检索它

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的条目。这样,您可以以相同的方式处理所有列表?这里需要一个公共接口/基类。