Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/334.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 - Fatal编程技术网

C# 如何动态收集闭合类型?

C# 如何动态收集闭合类型?,c#,generics,reflection,C#,Generics,Reflection,假设我有一个泛型类,定义如下: public class MyThing<T> { private static int NumberOfCallsToFoo; public void Foo(T item) { NumberOfCallsToFoo++; ... } } 然后我可以使用反射来获取NumberOfCallsToFoo字段。其目的是跟踪一个包含许多类型和程序集的大型系统 更新: 我试着重新制定我需要

假设我有一个泛型类,定义如下:

public class MyThing<T> {
     private static int NumberOfCallsToFoo;
     public void Foo(T item) {
          NumberOfCallsToFoo++;
          ...
     }
}
然后我可以使用反射来获取
NumberOfCallsToFoo
字段。其目的是跟踪一个包含许多类型和程序集的大型系统

更新
我试着重新制定我需要的东西。在程序执行的任意时刻,我想收集某个泛型类型的所有(迄今为止构造的)封闭类型(不是实例)。

在运行时这样做是不可能的,.NET不会公开一组“我创建过的此类型的所有实例”。所以你需要调整一些代码来收集你自己想要的东西。以下是一些选项:

错误选项(从技术上解决您的问题):

公共类跟踪器
{
公共静态列表类型=新列表();
}
公共阶级神话
{
静态神话()
{
//这是静态构造函数,每种类型调用一次
Tracker.Types.Add(typeof(MyThing));
}
}
更好的选择。。。不存储类型,只需直接收集您想要的:

public class Tracker
{
    public static int NumberOfCallsToFoo;
}

public class MyThing<T>
{
    public void Foo(T item) {
        Tracker.NumberOfCallsToFoo++;
        ...
    }
}
公共类跟踪器
{
公共静态int NumberOfCallsToFoo;
}
公共阶级神话
{
公开作废Foo(T项){
Tracker.NumberOfCallsToFoo++;
...
}
}

我相信,除非您自己提供,否则您在运行时查找的信息根本不可用。其他类似的问题也强化了这一信念,例如

不幸的是,自己完成这项工作需要检测您想要跟踪的每个泛型类型。如果你只有一个,可能就好了。但对每种泛型类型都这样做可能会有点乏味。在这种情况下,我可能更愿意研究AoP工具(例如PostSharp),它允许您以更自动化的方式添加此工具

也就是说,考虑到你的问题陈述,我可能会这样处理:

class C
{
    protected static List<Type> _types = new List<Type>();

    public static void ReportCounts()
    {
        foreach (Type type in _types)
        {
            FieldInfo fi = type.GetField("_count", BindingFlags.Static | BindingFlags.NonPublic);

            Console.WriteLine($"{type.Name}: {fi.GetValue(null)}");
        }
    }
}

class C<T> : C
{
    static int _count;

    static C()
    {
        _types.Add(typeof(C<T>));
    }

    public void M()
    {
        _count++;
    }
}
演示程序:

class Program
{
    static void Main(string[] args)
    {
        C<int> c1 = new C<int>();
        C<bool> c2 = new C<bool>();

        c1.M();
        c2.M();
        c2.M();

        C.ReportCounts();
    }
}
class Program
{
    static void Main(string[] args)
    {
        C<int> c1 = new C<int>();
        C<bool> c2 = new C<bool>();

        c1.M1();
        c1.M2();
        c1.M2();
        c2.M1();
        c2.M1();
        c2.M1();
        c2.M2();
        c2.M2();
        c2.M2();
        c2.M2();

        C.ReportCounts();
    }
}
类程序
{
静态void Main(字符串[]参数)
{
C c1=新的C();
C c2=新的C();
c1.M1();
c1.M2();
c1.M2();
c2.M1();
c2.M1();
c2.M1();
c2.M2();
c2.M2();
c2.M2();
c2.M2();
C.报告计数();
}
}
收益率:

C`1: 1 C`1: 2 C.M1: 1 C.M2: 2 C.M1: 3 C.M2: 4 C.M1:1 C.M2:2 C.M1:3
C.M2:4您可以在运行时执行此操作,但必须修改代码

首先,声明一个静态全局字符串列表,其中包含闭合类型的全名,以及一个用于向其中添加的方法:

class Program
{
    static public List<string> _closedTypes = new List<string>();

    static public void RegisterClosedType(Type t)
    {
        _closedTypes.Add(String.Format("{0}<{1}>",
            t.Name.Split('`')[0],
            String.Join(",", t.GenericTypeArguments.Select(q => q.Name))
            ));
    }
}
类程序
{
静态公共列表_closedTypes=新列表();
静态公共无效注册表ClosedType(类型t)
{
_closedTypes.Add(String.Format(“{0}”),
t、 Name.Split('`')[0],
String.Join(“,”,t.GenericTypeArguments.Select(q=>q.Name))
));
}
}
然后向每个泛型类型添加一个静态构造函数。我们将利用这样一个事实,即静态构造函数对于每个闭合类型只运行一次,即将有一个调用
SomeGenericType
,第二个调用
SomeGenericType
。例如:

class SomeGenericType<T>
{
    static SomeGenericType()
    {
        Program.RegisterClosedType(typeof(SomeGenericType<T>));    
    }
}
class SomeGenericType
{
静态SomeGenericType()
{
Program.RegisterClosedType(typeof(SomeGenericType));
}
}
最终课程:

class Program
{
    static public List<string> _closedTypes = new List<string>();

    static public void RegisterClosedType(Type t)
    {
        _closedTypes.Add(String.Format("{0}<{1}>",
            t.Name.Split('`')[0],
            String.Join(",", t.GenericTypeArguments.Select(q => q.Name))
            ));
    }

    static public void Main()
    {
        var d = new SomeGenericType<double>();
        var i = new SomeGenericType<int>();

        DumpClosedTypes();
    }

    static void DumpClosedTypes()
    {
        foreach (var s in _closedTypes)
        {
            Console.WriteLine(s);
        }
    }
}
类程序
{
静态公共列表_closedTypes=新列表();
静态公共无效注册表ClosedType(类型t)
{
_closedTypes.Add(String.Format(“{0}”),
t、 Name.Split('`')[0],
String.Join(“,”,t.GenericTypeArguments.Select(q=>q.Name))
));
}
静态公共void Main()
{
var d=新的SomeGenericType();
var i=新的SomeGenericType();
DumpClosedTypes();
}
静态void DumpClosedTypes()
{
foreach(关闭类型中的var s)
{
控制台。写入线(s);
}
}
}
运行它,输出为:

SomeGenericType<Double>
SomeGenericType<Int32>
SomeGenericType
某些泛型

您可以使用reflection
GetType().Name
获取类型名称。挑战不在于如何获取名称,也不在于如何获取
NumberOfCalls
字段,而在于获取所有已关闭的类型。我不相信您可以。。。手动跟踪类型列表可能是唯一的选项(与您必须编写的任何反射相比,实现/理解它肯定是微不足道的)“我需要的是一种从运行时动态获取所有创建的封闭类型的方法”——这怎么不是完全相同的问题?它如何不遭受和问题相同的固有问题呢?手动跟踪可能是一种选择。但是,运行时也需要跟踪它。所以我想知道是否有办法从运行时检索这些信息。当然,我可以手动跟踪。顺便说一句,第二个选项不是一个选项,因为我想知道每个泛型参数类型的调用次数(请参见我的问题)。您可以使用类似于
Tracker.IncrementCalls(typeof(T))
的方法将泛型类型发送到
Tracker
。感谢所有详细信息。这是豪华的手动跟踪解决方案,在静态c'tor中注册-我想到了这一点。然而,我的希望是通过某种方式从系统中获取这些信息——因为它就在附近的某个地方。谢谢。基本上,与Peter Duniho的方法相同。是的,我为他写了这个答案,但没有看到他的答案。我的回答还显示了如何获取泛型类型参数,这似乎很重要。是的。抱歉弄得一团糟:(
class Program
{
    static public List<string> _closedTypes = new List<string>();

    static public void RegisterClosedType(Type t)
    {
        _closedTypes.Add(String.Format("{0}<{1}>",
            t.Name.Split('`')[0],
            String.Join(",", t.GenericTypeArguments.Select(q => q.Name))
            ));
    }

    static public void Main()
    {
        var d = new SomeGenericType<double>();
        var i = new SomeGenericType<int>();

        DumpClosedTypes();
    }

    static void DumpClosedTypes()
    {
        foreach (var s in _closedTypes)
        {
            Console.WriteLine(s);
        }
    }
}
SomeGenericType<Double>
SomeGenericType<Int32>