using System.Diagnostics; namespace ConsoleApp1 { internal interface IValueGetter { int GetValue(int index); } internal class MyTestClass<T> where T : IValueGetter { private readonly T _valueGetter; public MyTestClass(T valueGetter) { _valueGetter = valueGetter; } public void Run() { long r = 0L; for (int i = 0; i < int.MaxValue; i++) { r += _valueGetter.GetValue(i); } } } internal struct StructValueGetter : IValueGetter { public readonly int GetValue(int index) { return index + 3; } } internal struct StructValueGetter2(int someField) : IValueGetter { public readonly int GetValue(int index) { return index + 5; } } internal class ClassValueGetter1 : IValueGetter { public int GetValue(int index) { return index + 5; } } internal class ClassValueGetter2 : IValueGetter { public int GetValue(int index) { return index + 7; } } internal static class Demo2 { public static void Run() { var t1 = new MyTestClass<StructValueGetter>(new StructValueGetter()); RunDemo("StructValueGetter ", t1.Run); var t2 = new MyTestClass<ClassValueGetter1>(new ClassValueGetter1()); RunDemo("ClassValueGetter1 ", t2.Run); var t3 = new MyTestClass<ClassValueGetter2>(new ClassValueGetter2()); RunDemo("ClassValueGetter2 ", t3.Run); var t4 = new MyTestClass<IValueGetter>(new ClassValueGetter1()); RunDemo("IValueGetter-1 ", t4.Run); var t5 = new MyTestClass<ClassValueGetter1>(new ClassValueGetter1()); RunDemo("ClassValueGetter1 ", t5.Run); var t6 = new MyTestClass<StructValueGetter2>(new StructValueGetter2()); RunDemo("StructValueGetter2", t6.Run); var t7 = new MyTestClass<IValueGetter>(new ClassValueGetter2()); RunDemo("IValueGetter-2 ", t7.Run); var t8 = new MyTestClass<IValueGetter>(new StructValueGetter()); RunDemo("IValueGetter-3 ", t8.Run); var t9 = Activator.CreateInstance(typeof(MyTestClass<>).MakeGenericType(typeof(StructValueGetter)), new StructValueGetter()); Action action9 = (Action)Delegate.CreateDelegate(typeof(Action), t9, t9.GetType().GetMethod("Run")); RunDemo("Dynamic-Struct ", action9); } static void RunDemo(string caption, Action action) { var stopWatch = Stopwatch.StartNew(); action(); stopWatch.Stop(); Console.WriteLine($"{caption} time = {stopWatch.Elapsed}"); } } } Demo2.Run();在.net 8.0 Release 编译执行的参考结果如下:
StructValueGetter time = 00:00:00.6920186 ClassValueGetter1 time = 00:00:01.1887137 ClassValueGetter2 time = 00:00:05.2889692 IValueGetter-1 time = 00:00:01.1652195 ClassValueGetter1 time = 00:00:01.1625259 StructValueGetter2 time = 00:00:00.6488674 IValueGetter-2 time = 00:00:05.2114724 IValueGetter-3 time = 00:00:07.1394676 Dynamic-Struct time = 00:00:00.6491220
4.使用反射(例如:MakeGenericType)构建出的泛型实例,其实际运行性能并不受影响,非常适合高度定制的运行时类型构建,这一点非常重要,例如你可以在运行时检测实际情况,构建出不同的比较器对象,虽然构建的工厂方法返回的是接口,但你可以使用反射的方式动态传入字典的比较器参数(实际上c#的 Dictionary<TKey, TValue> 这点设计是失败的,他的comparer不是一个泛型参数,而是接口);