Typ (T) vs. TypeOf⟨T⟩

Manchmal sind reflektierende Herausforderungen im Hinblick auf die Produktivität teuer und können nicht ausgelassen werden.

In diesem Artikel werden Muster vorgestellt, mit denen die Leistung mehrerer reflexiver Aufrufe durch Virtualisierung (Caching) von Ergebnissen erheblich gesteigert werden kann.

Bild

Betrachten Sie die folgende Methode:

static void AnyPerformanceCriticalMethod()
{
	var anyTypeName = typeof(AnyType).Name;
	/* ... using of anyTypeName ... */
}

— , :

/* much better! */
static readonly string AnyTypeName = typeof(AnyType).Name;

static void AnyPerformanceCriticalMethod()
{
	/* ... using of AnyTypeName ... */
}

(generic) ?

static void AnyPerformanceCriticalMethod<T>()
{
	var anyTypeName = typeof(T).Name;
	/* ... using of anyTypeName ... */
}

, .

TypeOf.cs
public static class TypeOf<T>
{
	/* Important! Should be a readonly variable for best performance */ 
	public static readonly Type Raw = typeof(T);
	
	public static readonly string Name = Raw.Name;
	public static readonly Assembly Assembly = Raw.Assembly;
	public static readonly bool IsValueType = Raw.IsValueType;
	/* etc. */
}

static void AnyPerformanceCriticalMethod<T>()
{
	var anyTypeName = TypeOf<T>.Name;
	/* ... using of anyTypeName ... */
}

*, , C# : `typeof`, `is`, `as`

?

static void AnyPerformanceCriticalMethod(object item)
{
	var itemTypeName = o.GetType().Name;
	/* ... using of anyTypeName ... */
}

.

RipeType.cs
public class RipeType
{
	internal RipeType(Type raw)
	{
		Raw = raw;
		
		Name = raw.Name;
		Assembly = raw.Assembly;
		IsValueType = raw.IsValueType;
		/* etc. */
	}

	public static Type Raw { get; }
	
	public string Name { get; }
	public Assembly Assembly { get; }
	public bool IsValueType { get; }
	/* etc. */
}

TypeOf.cs
* : , ConcurrentDictionary ( )
public static class TypeOf
{
	private static readonly object SyncRoot = new object();

	private static readonly Dictionary<Type, RipeType> RawToRipe = new Dictionary<Type, RipeType>();

	public static RipeType ToRipeType(this Type type) =>
		RawToRipe.TryGetValue(type, out var typeData)
			? typeData
			: Lock.Invoke(SyncRoot, () => RawToRipe.TryGetValue(type, out typeData)
				? typeData // may catch item created into a different thread
				: RawToRipe[type] = new RipeType(type));
				
	public static RipeType GetRipeType(this object o) => o.GetType().ToRipeType();
}

Lock.cs
public static class Lock
{
	public static void Invoke<TSyncContext>(TSyncContext customSyncContext, Action action)
	{
		lock (customSyncContext) action();
	}

	public static TResult Invoke<TSyncContext, TResult>(TSyncContext customSyncContext, Func<TResult> func)
	{
		lock (customSyncContext) return func();
	}
}

, :

static void AnyPerformanceCriticalMethod(object item)
{
	var itemTypeName = o.GetRipeType().Name;
	/* ... using of anyTypeName ... */
}

`TypeOf` ?
* `typeof(List<>)`
* `TypeOf<List<>>`

?

var listAssemby = TypeOf.List.Assembly;



public static class TypeOf
{
	/* ... */

	public static readonly RipeType Object = typeof(object).ToRipeType();
	public static readonly RipeType String = typeof(string).ToRipeType();
	public static readonly RipeType Array = typeof(Array).ToRipeType();
	public static readonly RipeType Type = typeof(Type).ToRipeType();
	public static readonly RipeType List = typeof(List<>).ToRipeType();
	public static readonly RipeType IList = typeof(IList<>).ToRipeType();
	public static readonly RipeType Dictionary = typeof(Dictionary<,>).ToRipeType();
	public static readonly RipeType IDictionary = typeof(IDictionary<,>).ToRipeType();
	public static readonly RipeType KeyValuePair = typeof(KeyValuePair<,>).ToRipeType();
	public static readonly RipeType DictionaryEntry = typeof(DictionaryEntry).ToRipeType();
}

!

typeof vs. TypeOf [BenchmarkDotNet - code]
[
	CoreJob,
	ClrJob,
	MonoJob("Mono", @"C:\Program Files\Mono\bin\mono.exe")
]
public class TypeOfBenchmarks
{
	[Benchmark] public Type typeof_int() => typeof(int);
	[Benchmark] public Type TypeOf_int() => TypeOf<int>.Raw;
	[Benchmark] public Type typeof_string() => typeof(string);
	[Benchmark] public Type TypeOf_string() => TypeOf<string>.Raw;

	[Benchmark] public string typeof_int_Name() => typeof(int).Name;
	[Benchmark] public string TypeOf_int_Name() => TypeOf<int>.Name;
	[Benchmark] public string typeof_string_Name() => typeof(string).Name;
	[Benchmark] public string TypeOf_string_Name() => TypeOf<string>.Name;
	
	[Benchmark] public Assembly typeof_int_Assembly() => typeof(int).Assembly;
	[Benchmark] public Assembly TypeOf_int_Assembly() => TypeOf<int>.Assembly;
	[Benchmark] public Assembly typeof_string_Assembly() => typeof(string).Assembly;
	[Benchmark] public Assembly TypeOf_string_Assembly() => TypeOf<string>.Assembly;
	
	[Benchmark] public bool typeof_int_IsValueType() => typeof(int).IsValueType;
	[Benchmark] public bool TypeOf_int_IsValueType() => TypeOf<int>.IsValueType;
	[Benchmark] public bool typeof_string_IsValueType() => typeof(string).IsValueType;
	[Benchmark] public bool TypeOf_string_IsValueType() => TypeOf<string>.IsValueType;
}


typeof vs. TypeOf [BenchmarkDotNet - results]
Total time: 00:23:34 (1414.47 sec)

// * Summary *

BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134
Intel Core i7-3517U CPU 1.90GHz (Ivy Bridge), 1 CPU, 4 logical and 2 physical cores
Frequency=2338440 Hz, Resolution=427.6355 ns, Timer=TSC
.NET Core SDK=2.1.302
  [Host] : .NET Core 2.1.2 (CoreCLR 4.6.26628.05, CoreFX 4.6.26629.01), 64bit RyuJIT
  Clr    : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3160.0
  Core   : .NET Core 2.1.2 (CoreCLR 4.6.26628.05, CoreFX 4.6.26629.01), 64bit RyuJIT
  Mono   : Mono 5.12.0 (Visual Studio), 64bit 


                    Method |  Job | Runtime |        Mean |      Error |     StdDev |
-------------------------- |----- |-------- |------------:|-----------:|-----------:|
                typeof_int |  Clr |     Clr |   3.2686 ns |  0.0490 ns |  0.0434 ns |
                TypeOf_int |  Clr |     Clr |   0.0495 ns |  0.1124 ns |  0.0939 ns |
             typeof_string |  Clr |     Clr |   3.1980 ns |  0.0288 ns |  0.0270 ns |
             TypeOf_string |  Clr |     Clr |   0.0520 ns |  0.0773 ns |  0.0723 ns |
           typeof_int_Name |  Clr |     Clr |  19.4201 ns |  0.1220 ns |  0.1141 ns |
           TypeOf_int_Name |  Clr |     Clr |   0.0082 ns |  0.0169 ns |  0.0159 ns |
        typeof_string_Name |  Clr |     Clr |  19.5041 ns |  0.1397 ns |  0.1090 ns |
        TypeOf_string_Name |  Clr |     Clr |   0.0007 ns |  0.0031 ns |  0.0028 ns |
       typeof_int_Assembly |  Clr |     Clr |  33.8565 ns |  0.6931 ns |  0.5788 ns |
       TypeOf_int_Assembly |  Clr |     Clr |   0.0034 ns |  0.0130 ns |  0.0115 ns |
    typeof_string_Assembly |  Clr |     Clr |  33.9922 ns |  0.2244 ns |  0.1989 ns |
    TypeOf_string_Assembly |  Clr |     Clr |   0.0001 ns |  0.0004 ns |  0.0003 ns |
    typeof_int_IsValueType |  Clr |     Clr |  56.1685 ns |  0.3858 ns |  0.3420 ns |
    TypeOf_int_IsValueType |  Clr |     Clr |   0.4990 ns |  0.0141 ns |  0.0132 ns |
 typeof_string_IsValueType |  Clr |     Clr |  94.0358 ns |  0.4386 ns |  0.3662 ns |
 TypeOf_string_IsValueType |  Clr |     Clr |   0.4960 ns |  0.0109 ns |  0.0102 ns |

                typeof_int | Core |    Core |   1.9114 ns |  0.0527 ns |  0.0493 ns |
                TypeOf_int | Core |    Core |   6.1310 ns |  0.0494 ns |  0.0462 ns |
             typeof_string | Core |    Core |   2.2120 ns |  0.0522 ns |  0.0436 ns |
             TypeOf_string | Core |    Core |   6.1174 ns |  0.0481 ns |  0.0401 ns |
           typeof_int_Name | Core |    Core |  19.5100 ns |  0.1998 ns |  0.1771 ns |
           TypeOf_int_Name | Core |    Core |   6.1495 ns |  0.0829 ns |  0.0735 ns |
        typeof_string_Name | Core |    Core |  19.3662 ns |  0.0895 ns |  0.0793 ns |
        TypeOf_string_Name | Core |    Core |   6.1589 ns |  0.0314 ns |  0.0278 ns |
       typeof_int_Assembly | Core |    Core |  23.4876 ns |  0.1885 ns |  0.1763 ns |
       TypeOf_int_Assembly | Core |    Core |   6.1362 ns |  0.0415 ns |  0.0388 ns |
    typeof_string_Assembly | Core |    Core |  25.5613 ns |  0.2293 ns |  0.2033 ns |
    TypeOf_string_Assembly | Core |    Core |   6.1082 ns |  0.0352 ns |  0.0312 ns |
    typeof_int_IsValueType | Core |    Core |  49.8048 ns |  0.2305 ns |  0.1925 ns |
    TypeOf_int_IsValueType | Core |    Core |   7.1171 ns |  0.0477 ns |  0.0423 ns |
 typeof_string_IsValueType | Core |    Core |  84.8155 ns |  0.7962 ns |  0.7058 ns |
 TypeOf_string_IsValueType | Core |    Core |   7.0987 ns |  0.0521 ns |  0.0487 ns |

                typeof_int | Mono |    Mono |   0.0725 ns |  0.0229 ns |  0.0214 ns |
                TypeOf_int | Mono |    Mono |   3.0123 ns |  0.0652 ns |  0.0610 ns |
             typeof_string | Mono |    Mono |   0.0185 ns |  0.0206 ns |  0.0193 ns |
             TypeOf_string | Mono |    Mono |   9.3828 ns |  0.0863 ns |  0.0765 ns |
           typeof_int_Name | Mono |    Mono | 429.8195 ns |  4.4049 ns |  3.6783 ns |
           TypeOf_int_Name | Mono |    Mono |   2.3856 ns |  0.1608 ns |  0.1426 ns |
        typeof_string_Name | Mono |    Mono | 439.3774 ns |  1.2985 ns |  1.2146 ns |
        TypeOf_string_Name | Mono |    Mono |   8.8580 ns |  0.0728 ns |  0.0646 ns |
       typeof_int_Assembly | Mono |    Mono | 223.5933 ns |  0.6152 ns |  0.5454 ns |
       TypeOf_int_Assembly | Mono |    Mono |   2.2587 ns |  0.0494 ns |  0.0462 ns |
    typeof_string_Assembly | Mono |    Mono | 227.3259 ns |  0.6448 ns |  0.5716 ns |
    TypeOf_string_Assembly | Mono |    Mono |   9.3276 ns |  0.1215 ns |  0.1136 ns |
    typeof_int_IsValueType | Mono |    Mono | 490.2376 ns |  4.3860 ns |  4.1027 ns |
    TypeOf_int_IsValueType | Mono |    Mono |   3.1849 ns |  0.0145 ns |  0.0129 ns |
 typeof_string_IsValueType | Mono |    Mono | 997.4254 ns | 11.6159 ns | 10.8655 ns |
 TypeOf_string_IsValueType | Mono |    Mono |   9.6504 ns |  0.0354 ns |  0.0331 ns |


Type vs. RipeType [BenchmarkDotNet - code]
[
	CoreJob,
	ClrJob,
	MonoJob("Mono", @"C:\Program Files\Mono\bin\mono.exe")
]
public class RipeTypeBenchmarks
{
	static object o = new object();
	readonly Type rawType = o.GetType();
	readonly RipeType ripeType = o.GetRipeType();
	
	[Benchmark] public string RawType_Name() => rawType.Name;
	[Benchmark] public string RipeType_Name() => ripeType.Name;
	[Benchmark] public string GetRawType_Name() => o.GetType().Name;
	[Benchmark] public string GetRipeType_Name() => o.GetRipeType().Name;

	[Benchmark] public Assembly RawType_Assembly() => rawType.Assembly;
	[Benchmark] public Assembly RipeType_Assembly() => ripeType.Assembly;
	[Benchmark] public Assembly GetRawType_Assembly() => o.GetType().Assembly;
	[Benchmark] public Assembly GetRipeType_Assembly() => o.GetRipeType().Assembly;

	[Benchmark] public bool RawType_IsValueType() => rawType.IsValueType;
	[Benchmark] public bool RipeType_IsValueType() => ripeType.IsValueType;
	[Benchmark] public bool GetRawType_IsValueType() => o.GetType().IsValueType;
	[Benchmark] public bool GetRipeType_IsValueType() => o.GetRipeType().IsValueType;
}


Type vs. RipeType [BenchmarkDotNet - results]
Total time: 00:14:59 (899.57 sec)

// * Summary *

BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134
Intel Core i7-3517U CPU 1.90GHz (Ivy Bridge), 1 CPU, 4 logical and 2 physical cores
Frequency=2338440 Hz, Resolution=427.6355 ns, Timer=TSC
.NET Core SDK=2.1.302
  [Host] : .NET Core 2.1.2 (CoreCLR 4.6.26628.05, CoreFX 4.6.26629.01), 64bit RyuJIT
  Clr    : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3160.0
  Core   : .NET Core 2.1.2 (CoreCLR 4.6.26628.05, CoreFX 4.6.26629.01), 64bit RyuJIT
  Mono   : Mono 5.12.0 (Visual Studio), 64bit


                  Method |  Job | Runtime |        Mean |     Error |    StdDev |
------------------------ |----- |-------- |------------:|----------:|----------:|
            RawType_Name |  Clr |     Clr |  10.2733 ns | 0.1112 ns | 0.1040 ns |
           RipeType_Name |  Clr |     Clr |   0.0164 ns | 0.0220 ns | 0.0206 ns |
         GetRawType_Name |  Clr |     Clr |  15.3661 ns | 0.4064 ns | 0.7431 ns |
        GetRipeType_Name |  Clr |     Clr |  43.3530 ns | 0.4160 ns | 0.3474 ns |
        RawType_Assembly |  Clr |     Clr |  19.8898 ns | 0.1967 ns | 0.1840 ns |
       RipeType_Assembly |  Clr |     Clr |   0.0002 ns | 0.0010 ns | 0.0009 ns |
     GetRawType_Assembly |  Clr |     Clr |  22.7084 ns | 0.1512 ns | 0.1340 ns |
    GetRipeType_Assembly |  Clr |     Clr |  43.1685 ns | 0.3532 ns | 0.3304 ns |
     RawType_IsValueType |  Clr |     Clr |  35.7668 ns | 0.2840 ns | 0.2517 ns |
    RipeType_IsValueType |  Clr |     Clr |   0.0005 ns | 0.0020 ns | 0.0018 ns |
  GetRawType_IsValueType |  Clr |     Clr |  39.6176 ns | 0.2465 ns | 0.2306 ns |
 GetRipeType_IsValueType |  Clr |     Clr |  43.4645 ns | 0.9240 ns | 0.8643 ns |
 
            RawType_Name | Core |    Core |  10.7102 ns | 0.1705 ns | 0.1511 ns |
           RipeType_Name | Core |    Core |   0.0075 ns | 0.0154 ns | 0.0144 ns |
         GetRawType_Name | Core |    Core |  12.8294 ns | 0.0698 ns | 0.0653 ns |
        GetRipeType_Name | Core |    Core |  38.7723 ns | 0.2665 ns | 0.2493 ns |
        RawType_Assembly | Core |    Core |  13.1644 ns | 0.0729 ns | 0.0682 ns |
       RipeType_Assembly | Core |    Core |   0.0174 ns | 0.0207 ns | 0.0194 ns |
     GetRawType_Assembly | Core |    Core |  15.3733 ns | 0.1252 ns | 0.1110 ns |
    GetRipeType_Assembly | Core |    Core |  38.7863 ns | 0.3133 ns | 0.2616 ns |
     RawType_IsValueType | Core |    Core |  32.9788 ns | 0.4456 ns | 0.3721 ns |
    RipeType_IsValueType | Core |    Core |   0.0365 ns | 0.0128 ns | 0.0107 ns |
  GetRawType_IsValueType | Core |    Core |  35.4362 ns | 0.2927 ns | 0.2595 ns |
 GetRipeType_IsValueType | Core |    Core |  39.8377 ns | 0.2895 ns | 0.2708 ns |
 
            RawType_Name | Mono |    Mono | 287.4362 ns | 2.3812 ns | 2.2274 ns |
           RipeType_Name | Mono |    Mono |   0.4614 ns | 0.0320 ns | 0.0299 ns |
         GetRawType_Name | Mono |    Mono | 288.2094 ns | 2.2540 ns | 2.1084 ns |
        GetRipeType_Name | Mono |    Mono |  54.3390 ns | 0.2807 ns | 0.2625 ns |
        RawType_Assembly | Mono |    Mono | 143.6474 ns | 0.7524 ns | 0.7038 ns |
       RipeType_Assembly | Mono |    Mono |   0.7015 ns | 0.0261 ns | 0.0244 ns |
     GetRawType_Assembly | Mono |    Mono | 144.0314 ns | 3.2279 ns | 3.0194 ns |
    GetRipeType_Assembly | Mono |    Mono |  54.5511 ns | 0.2955 ns | 0.2619 ns |
     RawType_IsValueType | Mono |    Mono | 277.4973 ns | 1.4938 ns | 1.3242 ns |
    RipeType_IsValueType | Mono |    Mono |   0.5206 ns | 0.0176 ns | 0.0156 ns |
  GetRawType_IsValueType | Mono |    Mono | 280.7464 ns | 2.1995 ns | 1.8367 ns |
 GetRipeType_IsValueType | Mono |    Mono |  58.5908 ns | 0.1690 ns | 0.1498 ns |


Manual benchmarks - Code (much faster runs)
using System;
using System.Diagnostics;
using System.Linq;
using Ace.Base.Benchmarking.Benchmarks;
using BenchmarkDotNet.Running;

namespace Ace.Base.Benchmarking
{
    static class Program
    {
        private const long WarmRunsCount = 1000;
        private const long HotRunsCount = 10000000; // 10 000 000

        static void Main()
        {
            //BenchmarkRunner.Run<TypeOfBenchmarks>();
            //BenchmarkRunner.Run<RipeTypeBenchmarks>();
            
            TypeofVsTypeOf();
            RawTypeVsRipeType();

            Console.ReadKey();
        }

        static void RawTypeVsRipeType()
        {
            Console.WriteLine();
            Console.WriteLine($"Count of warm iterations: {WarmRunsCount}");
            Console.WriteLine($"Count of hot iterations: {HotRunsCount}");
            Console.WriteLine();
            var o = new object();
            var rawType = o.GetType();
            var ripeType = o.GetRipeType();

            RunBenchmarks(
                (() => rawType.Name, "() => rawType.Name"),
                (() => ripeType.Name, "() => ripeType.Name"),
                (() => o.GetType().Name, "() => o.GetType().Name"),
                (() => o.GetRipeType().Name, "() => o.GetRipeType().Name")
            );

            Console.WriteLine();

            RunBenchmarks(
                (() => rawType.Assembly, "() => rawType.Assembly"),
                (() => ripeType.Assembly, "() => ripeType.Assembly"),
                (() => o.GetType().Assembly, "() => o.GetType().Assembly"),
                (() => o.GetRipeType().Assembly, "() => o.GetRipeType().Assembly")
            );

            Console.WriteLine();

            RunBenchmarks(
                (() => rawType.IsValueType, "() => rawType.IsValueType"),
                (() => ripeType.IsValueType, "() => ripeType.IsValueType"),
                (() => o.GetType().IsValueType, "() => o.GetType().IsValueType"),
                (() => o.GetRipeType().IsValueType, "() => o.GetRipeType().IsValueType")
            );
        }

        static void TypeofVsTypeOf()
        {
            Console.WriteLine($"Count of warm iterations: {WarmRunsCount}");
            Console.WriteLine($"Count of hot iterations: {HotRunsCount}");
            Console.WriteLine();

            RunBenchmarks(
                (() => typeof(int), "() => typeof(int)"),
                (() => TypeOf<int>.Raw, "() => TypeOf<int>.Raw"),
                (() => typeof(string), "() => typeof(string)"),
                (() => TypeOf<string>.Raw, "() => TypeOf<string>.Raw")
            );

            Console.WriteLine();

            RunBenchmarks(
                (() => typeof(int).Name, "() => typeof(int).Name"),
                (() => TypeOf<int>.Name, "() => TypeOf<int>.Name"),
                (() => typeof(string).Name, "() => typeof(string).Name"),
                (() => TypeOf<string>.Name, "() => TypeOf<string>.Name")
            );

            Console.WriteLine();

            RunBenchmarks(
                (() => typeof(int).Assembly, "() => typeof(int).Assembly"),
                (() => TypeOf<int>.Assembly, "() => TypeOf<int>.Assembly"),
                (() => typeof(string).Assembly, "() => typeof(string).Assembly"),
                (() => TypeOf<string>.Assembly, "() => TypeOf<string>.Assembly")
            );

            Console.WriteLine();

            RunBenchmarks(
                (() => typeof(int).IsValueType, "() => typeof(int).IsValueType"),
                (() => TypeOf<int>.IsValueType, "() => TypeOf<int>.IsValueType"),
                (() => typeof(string).IsValueType, "() => typeof(string).IsValueType"),
                (() => TypeOf<string>.IsValueType, "() => TypeOf<string>.IsValueType")
            );
        }

        static void RunBenchmarks<T>(params (Func<T> Func, string StringRepresentation)[] funcAndViewTuples) =>
            funcAndViewTuples
                .Select(t => (
                    BenchmarkResults: t.Func.InvokeBenchmark(HotRunsCount, WarmRunsCount),
                    StringRepresentation: t.StringRepresentation))
                .ToList().ForEach(t =>
                    Console.WriteLine(
                        $"{t.StringRepresentation}\t{t.BenchmarkResults.Result}\t{t.BenchmarkResults.ElapsedMilliseconds} (ms)"));

        static (Func<T> Func, long ElapsedMilliseconds, T Result) InvokeBenchmark<T>(this Func<T> func,
            long hotRunsCount, long warmRunsCount)
        {
            var stopwatch = new Stopwatch();
            var result = default(T);

            for (var i = 0L; i < warmRunsCount; i++)
                result = func();

            stopwatch.Start();
            for (var i = 0L; i < hotRunsCount; i++)
                result = func();

            stopwatch.Stop();
            return (func, stopwatch.ElapsedMilliseconds, result);
        }
    }
}


Manual benchmarks - Results on Core CLR

Count of warm iterations: 1000
Count of hot iterations: 10000000

() => typeof(int)       System.Int32    70 (ms)
() => TypeOf<int>.Raw   System.Int32    106 (ms)
() => typeof(string)    System.String   70 (ms)
() => TypeOf<string>.Raw        System.String   101 (ms)

() => typeof(int).Name  Int32   249 (ms)
() => TypeOf<int>.Name  Int32   42 (ms)
() => typeof(string).Name       String  245 (ms)
() => TypeOf<string>.Name       String  48 (ms)

() => typeof(int).Assembly      System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e       285 (ms)
() => TypeOf<int>.Assembly      System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e       42 (ms)
() => typeof(string).Assembly   System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e       340 (ms)
() => TypeOf<string>.Assembly   System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e       47 (ms)

() => typeof(int).IsValueType   True    544 (ms)
() => TypeOf<int>.IsValueType   True    53 (ms)
() => typeof(string).IsValueType        False   889 (ms)
() => TypeOf<string>.IsValueType        False   47 (ms)

Count of warm iterations: 1000
Count of hot iterations: 10000000

() => rawType.Name      Object  221 (ms)
() => ripeType.Name     Object  42 (ms)
() => o.GetType().Name  Object  250 (ms)
() => o.GetRipeType().Name      Object  687 (ms)

() => rawType.Assembly  System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e       271 (ms)
() => ripeType.Assembly System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e       42 (ms)
() => o.GetType().Assembly      System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e       330 (ms)
() => o.GetRipeType().Assembly  System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e       686 (ms)

() => rawType.IsValueType       False   553 (ms)
() => ripeType.IsValueType      False   47 (ms)
() => o.GetType().IsValueType   False   590 (ms)
() => o.GetRipeType().IsValueType       False   711 (ms)





`TypeOf` `RipeType` CLR.

Source: https://habr.com/ru/post/de419511/


All Articles