簡體   English   中英

如何僅使用System.Type / reflection獲得對通用單例實例的引用

[英]How to I get reference to generic singleton instance using only System.Type/reflection

我創建了一個簡單的性能測試類,它是一個singlton,它使用泛型PerformanceTesting<T>.Instance

(完整的源代碼可在我的博客文章中找到,但它不是最新版本http://www.createdbyx.com/post/2013/03/27/Code-Snippets-12-%E2%80%93 -Performance-Testing.aspx

這使開發人員可以使用他們更喜歡使用的東西作為訪問鍵,無論它是字符串,整數還是枚舉等。

因此,一切工作都很好,但是我試圖建立一個性能報告窗口,並且我希望能夠從所有實例化的singlton實例中收集性能數據,而不是PerformanceTesting<int> or PerformanceTesting<string>等。

我認為可以做到這一點的唯一方法是使用反射。 我還應該提到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;
        }
    }

一個簡化的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
    }
}

我正在使用此方法嘗試將結果報告給調試日志...

   /// <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);
    }

我遇到的問題在於PerformanceTestingTypes.GetTesting()方法內。 我需要僅使用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;

或換一種說法,如果我所擁有的只是一個變量“類型”(即引用int的System.Type),我將如何使用反射來獲取PerformanceTesting<int>的類型。

從技術上講,我認為我可以嘗試在字符串內部創建並構建一個C#類,然后將該字符串編譯為內存中的程序集,然后調用該類以獲取對我所需的單例的引用,但是這似乎過頭了,我懷疑我可能以及投放時遇到相同或相似的問題。

這甚至可能嗎?還是我試圖做不可能的事情? 希望我的問題有道理。 我的大腦已決定對此進行休整。 :(

嘗試這個:

var performanceTestingType = typeof(PerformanceTesting<>);
Type[] typeArgs = { typeof(int) };
var genericType = performanceTestingType.MakeGenericType(typeArgs);
object performanceTestingOfTypeInt = Activator.CreateInstance(genericType);

MSDN文章在這里

對於那些訪問此頁面並尋找相似答案的人,我要感謝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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM