I got the impression that in .NET casting (not convertting) is very cheap and fast. However, this does not look like an array. I am trying to make a very simple throw here, take T1 [] and throw as T2 []. where T1: T2.
There are 3 ways to do this, and I call them the following:
DropCasting: T2[] array2 = array; CastClass: (T2[])array; IsInst: array as T2[];
And I created methods for this, unfortunately, C # seems to be creating some rather strange code depending on whether this is common or not. (If its generic DropCasting uses the castclass operator. And in both cases refuse to give out an "how" operator when T1: T2.
In any case, I wrote some dynamic methods, and I checked it for some unexpected results (line [] => object []):
DropCast : 223ms IsInst : 3648ms CastClass: 3732ms
Dropcasting was ~ 18 times faster than any of the broadcast operators. Why is arrays too slow? For ordinary objects, such as string => object, the difference was much less serious.
DropCast : 386ms IsInst : 611ms CastClass: 519ms
Code below:
class Program { static readonly String[] strings = Enumerable.Range(0, 10).Select(x => x.ToString()).ToArray(); static Func<string[], object[]> Dropcast = new Func<Func<string[], object[]>>( () => { var method = new DynamicMethod("DropCast", typeof(object[]), new[] { typeof(object), typeof(string[]) },true); var ilgen = method.GetILGenerator(); ilgen.Emit(OpCodes.Ldarg_1); ilgen.Emit(OpCodes.Ret); return method.CreateDelegate(typeof(Func<string[], object[]>)) as Func<string[], object[]>; })(); static Func<string[], object[]> CastClass = new Func<Func<string[], object[]>>( () => { var method = new DynamicMethod("CastClass", typeof(object[]), new[] { typeof(object), typeof(string[]) },true); var ilgen = method.GetILGenerator(); ilgen.Emit(OpCodes.Ldarg_1); ilgen.Emit(OpCodes.Castclass, typeof(object[])); ilgen.Emit(OpCodes.Ret); return method.CreateDelegate(typeof(Func<string[], object[]>)) as Func<string[], object[]>; })(); static Func<string[], object[]> IsInst = new Func<Func<string[], object[]>>( () => { var method = new DynamicMethod("IsInst", typeof(object[]), new[] { typeof(object), typeof(string[]) },true); var ilgen = method.GetILGenerator(); ilgen.Emit(OpCodes.Ldarg_1); ilgen.Emit(OpCodes.Isinst, typeof(object[])); ilgen.Emit(OpCodes.Ret); return method.CreateDelegate(typeof(Func<string[], object[]>)) as Func<string[], object[]>; })(); static Func<string[], object[]>[] Tests = new Func<string[], object[]>[]{ Dropcast, IsInst, CastClass }; static void Main(string[] args) { int maxMethodLength = Tests.Select(x => GetMethodName(x.Method).Length).Max(); RunTests(1, false, maxMethodLength); RunTests(100000000, true, maxMethodLength); } static string GetMethodName(MethodInfo method) { return method.IsGenericMethod ? string.Format(@"{0}<{1}>", method.Name, string.Join<Type>(",", method.GetGenericArguments())) : method.Name; } static void RunTests(int count, bool displayResults, int maxLength) { foreach (var action in Tests) { Stopwatch sw = Stopwatch.StartNew(); for (int i = 0; i < count; i++) { action(strings); } sw.Stop(); if (displayResults) { Console.WriteLine("{0}: {1}ms", GetMethodName(action.Method).PadRight(maxLength), ((int)sw.ElapsedMilliseconds).ToString().PadLeft(6)); } GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); } } }
Edit before anyone asks the same thing is true for things like int [] → uint [], which clr specs should be distinguished without conversion.