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
某些泛型
您可以使用reflectionGetType().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>