Miałem wrażenie, że w .NET casting (nie konwertowanie) jest bardzo tanie i szybkie. Jednak wydaje się, że nie ma to miejsca w przypadku tablicy. Próbuję wykonać tutaj bardzo prostą obsadę, weź T1 [] i rzuć jako T2 []. gdzie T1: T2.Dlaczego przesyłanie tablic (wektorów) jest tak wolne?
Istnieją 3 sposoby, aby to zrobić i jestem nazywając je następujące ::
DropCasting: T2[] array2 = array;
CastClass: (T2[])array;
IsInst: array as T2[];
I stworzył sposoby, aby to zrobić, niestety, C# zdaje się tworzyć pewne dość dziwny kod w zależności od tego, czy jest ogólny lub nie. (Jeśli generyczny DropCasting używa operatora castclass iw obu przypadkach odmawia emisji 'as' operatora, gdy T1: T2.
W każdym razie napisałem kilka metod dynamicznych i przetestowałem je na kilka zaskakujących wyników (string [] => Object []):.?
DropCast : 223ms
IsInst : 3648ms
CastClass: 3732ms
Dropcasting było ~ 18 razy szybciej niż którykolwiek z operatorów odlewanych Dlaczego rzuca tak powolny dla tablic dla normalnych obiektach takich jak String => obiekt, różnica była znacznie mniejsza poważne:
DropCast : 386ms
IsInst : 611ms
CastClass: 519ms
Benchmark code bel OW:
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 zanim ktokolwiek pyta samo prawdziwe rzeczy jak int [] -> uint [], który specyfikacje CLR powinny być oddane bez konwersji.
Chodziło o to, aby masować IL w prawo.W niezwykle trywialnej metodzie, jak '() => ciągi znaków jako obiekt [];' kompilator usunie metodę 'as'. Tworzenie metody dynamicznej uruchamiane jest tylko raz w '.cctor' programu. Po tym każda metoda jest po prostu blobem IL. Dodałem też "instancję" do każdej metody dynamicznej (parametr obiektu), aby uniknąć tasowania podczas używania delegata w metodzie statycznej. –
Tak, przegapiłem drugą warstwę funcs podczas czytania za pierwszym razem. Usunąłem swój komentarz. ;) –
Objęte już kilkakrotnie, tylko można znaleźć stronę główną: http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two -array-covariance.aspx –