[英]How to I get reference to generic singleton instance using only System.Type/reflection
I created a simple performance testing class that is a singlton and it uses generics PerformanceTesting<T>.Instance
我创建了一个简单的性能测试类,它是一个singlton,它使用泛型
PerformanceTesting<T>.Instance
(Full source code available on my blog post, but it is not the most up to date version http://www.createdbyx.com/post/2013/03/27/Code-Snippets-12-%E2%80%93-Performance-Testing.aspx ) (完整的源代码可在我的博客文章中找到,但它不是最新版本http://www.createdbyx.com/post/2013/03/27/Code-Snippets-12-%E2%80%93 -Performance-Testing.aspx )
This allows the developer to use what ever they are more comfortable using as the accessor key whether it be a string, integer or enum etc. 这使开发人员可以使用他们更喜欢使用的东西作为访问键,无论它是字符串,整数还是枚举等。
So everything worked great but I am attempting to build a performance reporting window and I want the ability to collect performance data from all the instanciated singlton instances wheather it be PerformanceTesting<int> or PerformanceTesting<string>
etc. 因此,一切工作都很好,但是我试图建立一个性能报告窗口,并且我希望能够从所有实例化的singlton实例中收集性能数据,而不是
PerformanceTesting<int> or PerformanceTesting<string>
等。
The only way I figure I can do this is through the use of reflection. 我认为可以做到这一点的唯一方法是使用反射。 I should also mention that the PerformanceTesting class makes use of another class to track the various types that are being used as accessor keys to the
PerformanceTesting<T>
singleton(s). 我还应该提到PerformanceTesting类利用另一个类来跟踪用作
PerformanceTesting<T>
单例的访问键的各种类型。
/// <summary>
/// Provides a lock object when a singleton reference need to be instantiated.
/// </summary>
private static object lockObject = new object();
/// <summary>
/// Gets a singleton instance of the <see cref="PerformanceTesting{T}"/> class.
/// </summary>
public static PerformanceTesting<T> Instance
{
get
{
if (singleton == null)
{
lock (lockObject)
{
singleton = new PerformanceTesting<T>();
PerformanceTestingTypes.Register<T>();
}
}
return singleton;
}
}
A stripped down simplified version of PerformanceTestingTypes class is ... 一个简化的PerformanceTestingTypes类的简化版本是...
public class PerformanceTestingTypes
{
private static PerformanceTestingTypes singleton;
private List<Type> types = new List<Type>();
public static PerformanceTestingTypes Instance
{
get
{
return singleton ?? (singleton = new PerformanceTestingTypes());
}
}
public static Type[] GetTypes()
{
var values = new Type[Instance.types.Count];
Instance.types.CopyTo(values, 0);
return values;
}
public static void Register<T>()
{
Instance.types.Add(typeof(T));
}
// can't return PerformanceTesting<T> because T is of System.Type not the actual accessor type.
public static PerformanceTesting<T> GetTesting<T>(T type)
{
var rootType = typeof(PerformanceTesting<>); // this is wrong but placed for example purposes!!!
var prop = rootType.GetProperty("Instance");
var reference = prop.GetGetMethod().Invoke(null, null);
return reference; // compile error because Invoke returns type System.Object
}
}
I am using this method to try and report out the results to the debug log ... 我正在使用此方法尝试将结果报告给调试日志...
/// <summary>
/// If the PERFORMANCE symbol is available will report the performance metric information out to the console.
/// </summary>
public static void ReportPerformanceTimes()
{
var result = string.Empty;
foreach (var type in PerformanceTestingTypes.GetTypes())
{
var perf = PerformanceTestingTypes.GetTesting(type);
var keyNames = PerformanceTestingTypes.GetKeyNames(type);
foreach (var name in keyNames)
{
var key = PerformanceTestingTypes.ConvertKey(name, type);
result += string.Format("{0} - Total: {1}ms Average: {2} Count: {3}\r\n", name, perf.TotalMilliseconds(key), perf.AverageMilliseconds(key), perf.GetStartCount(key));
}
result += string.Format("Total Performance Times - Total: {0}ms", perf.TotalMilliseconds(perf.GetKeys()));
}
Debug.Log(result);
}
My problem I'm having lies within the PerformanceTestingTypes.GetTesting() method. 我遇到的问题在于PerformanceTestingTypes.GetTesting()方法内。 I need to return a reference to a specific instance of a generic singleton using only a System.Type that references the actual type that the singleton uses as it's accessor key.
我需要仅使用System.Type返回对通用单例的特定实例的引用,该System.Type引用单例用作其访问者键的实际类型。
var type = typeof(int); // the accessor key type that was used
// from the 'type' variable get a reference to singleton
var reference = PerformanceTesting<int>.Instance;
Or to put it another way how would I use reflection to get the type for PerformanceTesting<int>
if all I have is a variable 'type' that is a System.Type that refers to int. 或换一种说法,如果我所拥有的只是一个变量“类型”(即引用int的System.Type),我将如何使用反射来获取
PerformanceTesting<int>
的类型。
Technically I thought I could try and just create and build a single C# class inside of a string and compile that string into a in memory assembly then call the class to get the reference to the singleton I need but it seems overkill and I suspect I may run into the same or similar issues as well as with casting. 从技术上讲,我认为我可以尝试在字符串内部创建并构建一个C#类,然后将该字符串编译为内存中的程序集,然后调用该类以获取对我所需的单例的引用,但是这似乎过头了,我怀疑我可能以及投放时遇到相同或相似的问题。
Is this even possible or am I trying to do the impossible? 这甚至可能吗?还是我试图做不可能的事情? Hope my question makes sense.
希望我的问题有道理。 My brain has decided to take a hiatus on this one.
我的大脑已决定对此进行休整。 :(
:(
For those of you who landed on this page looking for a similar answer I am providing the resulting method for how I achieved my goal thanks to jaywayco's answer. 对于那些访问此页面并寻找相似答案的人,我要感谢jaywayco的答案,以其为最终实现目标的方法。
private void DrawPerformanceMetricsFlatList()
{
foreach (var type in PerformanceTestingTypes.GetTypes())
{
var performanceTestingType = typeof(PerformanceTesting<>);
Type[] typeArgs = { type };
var genericType = performanceTestingType.MakeGenericType(typeArgs);
var data = genericType.GetProperty("Instance", BindingFlags.GetProperty | BindingFlags.Static | BindingFlags.Public).GetGetMethod().Invoke(null, null);
var totalMilli = data.GetType().GetMethod("TotalMilliseconds", new[] { type });
var avgMilli = data.GetType().GetMethod("AverageMilliseconds", new[] { type });
var totalTicks = data.GetType().GetMethod("TotalTicks", new[] { type });
var avgTicks = data.GetType().GetMethod("AverageTicks", new[] { type });
var startCount = data.GetType().GetMethod("GetStartCount", new[] { type });
var fromConverter = data.GetType().GetProperty("ConvertFromStringCallback");
// var toConverter = data.GetType().GetProperty("ConvertToStringCallback", new[] { type });
var func = fromConverter.GetGetMethod().Invoke(data, null);
var invoker = func.GetType().GetMethod("Invoke");
var keyNames = PerformanceTestingTypes.GetKeyNames(type);
switch (this.sortIndex)
{
case 1:
keyNames = keyNames.OrderBy(x => x).ToArray();
break;
case 2:
keyNames = keyNames.OrderByDescending(x => totalTicks.Invoke(data, new[] { invoker.Invoke(func, new[] { x }) })).ToArray();
break;
case 3:
keyNames = keyNames.OrderByDescending(x => avgTicks.Invoke(data, new[] { invoker.Invoke(func, new[] { x }) })).ToArray();
break;
case 4:
keyNames = keyNames.OrderByDescending(x => startCount.Invoke(data, new[] { invoker.Invoke(func, new[] { x }) })).ToArray();
break;
}
ControlGrid.DrawGenericGrid((items, index, style, options) =>
{
var value = items[index];
var selected = GUILayout.Toggle(this.selectedIndex == index, value, style);
if (selected)
{
this.selectedIndex = index;
var key = invoker.Invoke(func, new[] { value });
this.performanceData = string.Format("{0}\r\nTotal: {1}ms ({4} ticks)\r\nAverage: {2}ms ({5} ticks)\r\nCount: {3}\r\n", value,
totalMilli.Invoke(data, new[] { key }),
avgMilli.Invoke(data, new[] { key }),
startCount.Invoke(data, new[] { key }),
totalTicks.Invoke(data, new[] { key }),
avgTicks.Invoke(data, new[] { key }));
}
return value;
}, keyNames, 1, GUI.skin.button);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.