我的印象是,在.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 –