我的印象是,在.NET鑄造(不轉換)是非常便宜和快速。但是,這似乎並不適用於數組。我想在這裏做一個非常簡單的演員,拍一個T1 []並且投射爲T2 []。其中T1:T2。爲什麼鑄造數組(向量)這麼慢?
有3種方法來做到這一點,我打電話給他們以下::
DropCasting: T2[] array2 = array;
CastClass: (T2[])array;
IsInst: array as T2[];
我創建的方法來做到這一點,不幸的是,C#似乎取決於如果這創造一些比較奇怪的代碼是通用還是不通用。 (如果它的泛型DropCasting使用了castclass操作符,並且在兩種情況下都拒絕在T1:T2時發出'as'操作符
無論如何,我寫了一些Dynamic方法,並且測試了一些令人驚訝的結果(string [] =>對象[]):?
DropCast : 223ms
IsInst : 3648ms
CastClass: 3732ms
Dropcasting比任鑄造運營商的更快〜18倍爲什麼是鑄造這麼慢數組 對於像字符串正常對象=>對象,差異少得多嚴重
DropCast : 386ms
IsInst : 611ms
CastClass: 519ms
基準代碼bel流量:
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();
}
}
}
人之前編輯問同樣保持真實的東西如int [] - > UINT []該CLR規格應無需轉換投。
重點是按摩IL的權利。在一個非常平凡的方法中,例如'()=> strings as object [];'編譯器將放棄'as'方法。動態方法創建僅在程序的'.cctor'處運行一次。之後,每種方法都只是IL blob。此外,我還爲每個動態方法(對象參數)添加了一個「實例」,只是爲了避免在靜態方法上使用委託時的thunk shuffle。 –
是的,我第一次閱讀時錯過了第二層功能。所以我刪除了我的評論。 ;) –
已涵蓋多次,只能找到主頁:http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two -array-covariance.aspx –