在System.Data.Linq中,EntitySet<T>
使用几个ItemList<T>
结构,如下所示:
internal struct ItemList<T> where T : class
{
private T[] items;
private int count;
...(methods)...
}
Run Code Online (Sandbox Code Playgroud)
(花了我比它应该发现的更长的时间 - 无法理解为什么实体字段EntitySet<T>
没有抛出空引用异常!)
我的问题是,将它作为一个类的结构实现它有什么好处?
由于这个问题是关于增量运算符和带前缀/后缀表示法的速度差异,我将非常仔细地描述这个问题,以免Eric Lippert发现它并激怒我!
(有关我为什么要问的更多信息和详细信息,请访问http://www.codeproject.com/KB/cs/FastLessCSharpIteration.aspx?msg=3899456#xx3899456xx/)
我有四个代码片段如下: -
(1)单独,前缀:
for (var j = 0; j != jmax;) { total += intArray[j]; ++j; }
Run Code Online (Sandbox Code Playgroud)
(2)单独,后缀:
for (var j = 0; j != jmax;) { total += intArray[j]; j++; }
Run Code Online (Sandbox Code Playgroud)
(3)Indexer,Postfix:
for (var j = 0; j != jmax;) { total += intArray[j++]; }
Run Code Online (Sandbox Code Playgroud)
(4)索引器,前缀:
for (var j = -1; j != last;) { total += intArray[++j]; } // last = jmax - 1
Run Code Online (Sandbox Code Playgroud)
我试图做的是证明/反驳在这个上下文中前缀和后缀表示法之间是否存在性能差异(即局部变量因此不易变,不能从另一个线程等变化)如果存在,为什么会出现这种情况.
速度测试表明:
(1)和(2)以相同的速度运行.
(3)和(4)以相同的速度运行.
(3)/(4)比(1)/(2)慢〜27%.
因此,我得出的结论是,在postfix表示法本身上选择前缀表示法没有性能优势.但是,当实际使用操作的结果 …
这段代码怎么样:
var check = 0;
for (var numerator = 0; numerator <= maxNumerator; numerator++)
{
check += numerator >= 0
? numerator - (int) ((numerator * qdi.Multiplier) >> qdi.Shift) * qdi.Number
: numerator - (int) -((-numerator * qdi.Multiplier) >> qdi.Shift) * qdi.Number;
}
return check;
Run Code Online (Sandbox Code Playgroud)
运行速度比此代码快3倍:
var check = 0;
for (var numerator = 0; numerator <= maxNumerator; numerator++)
{
check += numerator >= 0
? (int) ((numerator * qdi.Multiplier) >> qdi.Shift)
: (int) -((-numerator * qdi.Multiplier) >> qdi.Shift);
} …
Run Code Online (Sandbox Code Playgroud) 这段代码今天抓住了我:
clientFile.ReviewMonth == null ? null : MonthNames.AllValues[clientFile.ReviewMonth.Value]
Run Code Online (Sandbox Code Playgroud)
clientFile.Review月是一个字节?在失败的情况下,它的值为null.预期的结果类型是字符串.
此代码中的例外情况
public static implicit operator string(LookupCode<T> code)
{
if (code != null) return code.Description;
throw new InvalidOperationException();
}
Run Code Online (Sandbox Code Playgroud)
正在评估评估的右侧,然后隐式转换为字符串.
但我的问题是,为什么右手边被评估,显然只应评估左手边?(文档说明"只评估两个表达式中的一个.")
顺便说一句,解决方案是将null转换为字符串 - 这有效但Resharper告诉我演员是多余的(我同意)
编辑:这与"为什么我需要在编译之前添加一个强制转换"类型的三元运算符问题不同.这里的要点是不需要强制转换来使其编译 - 只是为了使其正常工作.
看看这个片段:
public class StringToggler
{
static readonly bool[] ToggleableLatinChars = new[]
{
// 256 bools here
};
readonly bool[] LocalToggleableLatinChars = ToggleableLatinChars;
public string Toggle(string s)
{
// blah blah
if (LocalToggleableLatinChars[(byte) ch])
{
// blah blah
}
// blah blah
}
// blah blah
}
Run Code Online (Sandbox Code Playgroud)
这个代码在测试中比我直接使用ToggleableLatinChars更快(7%ish).(在方法中使用对ToggleableLatinChars的本地引用也可以更快地使用相同的量).
只有在编译.NET 4时才会注意到这种效果.编译.NET 3.5时,我看到相反的效果 - 使用静态数组明显更快.(我的机器是运行Windows 7 64位的Intel i5,正在为x86编译)
知道为什么吗?
更新:这是一个完整的代码示例,更类似于Marc的测试样本.注意我现在使用静态和局部变量版本(不再是成员变量).虽然我看到的差异比我原来的测试代码看到的要少,但是当编译为.NET 4时,本地版本总是更快.您可以交换正在运行的订单,但Local总是为我赢.(为.NET 3.5编译不会这样做:它总体上比.NET 4快得多,静态要么更快或相同)
using System;
using System.Diagnostics;
using System.Globalization;
internal class Program
{
const int RepeatCount = 500000;
const string TestString1_Unicode = @"?=3.1415926?!! …
Run Code Online (Sandbox Code Playgroud) 这段代码工作正常:
policy.ProviderID > 0 ? RefDataSources.LegalBodies.GetDisplayName(policy.ProviderID.Value) : null
Run Code Online (Sandbox Code Playgroud)
但是Resharper抱怨policy.ProviderID.Value
需要null
检查(以防止InvalidOperationException
).
据我所知,条件只会对大于的非空值进行求值,0
因此不需要进一步检查.
我应该将此记录为JetBrains的错误吗?或者我误解了什么.
c# ×6
optimization ×2
performance ×2
evaluation ×1
il ×1
jit ×1
linq ×1
null ×1
resharper ×1
struct ×1
x86 ×1
x86-64 ×1