在C#中使用lambda表达式或匿名方法时,我们必须警惕对修改后的闭包陷阱的访问.例如:
foreach (var s in strings)
{
query = query.Where(i => i.Prop == s); // access to modified closure
...
}
Run Code Online (Sandbox Code Playgroud)
由于修改后的闭包,上面的代码将导致Where查询中的所有子句都基于最终值s.
正如这里所解释的那样,这是因为上面循环中s声明的变量foreach在编译器中被翻译成这样:
string s;
while (enumerator.MoveNext())
{
s = enumerator.Current;
...
}
Run Code Online (Sandbox Code Playgroud)
而不是像这样:
while (enumerator.MoveNext())
{
string s;
s = enumerator.Current;
...
}
Run Code Online (Sandbox Code Playgroud)
正如这里所指出的,在循环外声明变量没有性能优势,在正常情况下,我能想到这样做的唯一原因是你计划在循环范围之外使用变量:
string s;
while (enumerator.MoveNext())
{
s = enumerator.Current;
...
}
var finalString = s;
Run Code Online (Sandbox Code Playgroud)
但是,foreach循环中定义的变量不能在循环外使用: …
我最近一直在优化/基准测试一些代码,并遇到了这种方法:
public void SomeMethod(Type messageType)
{
if (messageType == typeof(BroadcastMessage))
{
// ...
}
else if (messageType == typeof(DirectMessage))
{
// ...
}
else if (messageType == typeof(ClientListRequest))
{
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
这是从其他地方的性能关键循环typeof(...)调用的,因此我自然地假设所有这些调用都增加了不必要的开销(我知道微优化)并且可以移动到类中的私有字段.(我知道有更好的方法来重构这些代码,但是,我仍然想知道这里发生了什么.)
根据我的基准测试,情况并非如此(使用BenchmarkDotNet).
[DisassemblyDiagnoser(printAsm: true, printSource: true)]
[RyuJitX64Job]
public class Tests
{
private Type a = typeof(string);
private Type b = typeof(int);
[Benchmark]
public bool F1()
{
return a == typeof(int);
}
[Benchmark]
public bool F2()
{
return a == b;
}
}
Run Code Online (Sandbox Code Playgroud)
在我的机器上的结果(Window …
我正在查看 IOrderedEnumerable 的声明,令我惊讶的是它的 TElement 类型参数不是协变的。
public interface IOrderedEnumerable<TElement> : IEnumerable<TElement>, IEnumerable
{
IOrderedEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending);
}
Run Code Online (Sandbox Code Playgroud)
它没有成为协变的原因是什么?
如果我有一个引发事件的类,使用(例如)FrobbingEventArgs,我是否可以使用带有EventArgs的方法来处理它?
这是一些代码:
class Program
{
static void Main(string[] args)
{
Frobber frobber = new Frobber();
frobber.Frobbing += FrobberOnFrobbing;
frobber.Frob();
}
private static void FrobberOnFrobbing(object sender,
EventArgs e)
{
// Do something interesting. Note that the parameter is 'EventArgs'.
}
}
internal class Frobber
{
public event EventHandler<FrobbingEventArgs> Frobbing;
public event EventHandler<FrobbedEventArgs> Frobbed;
public void Frob()
{
OnFrobbing();
// Frob.
OnFrobbed();
}
private void OnFrobbing()
{
var handler = Frobbing;
if (handler != null)
handler(this, new FrobbingEventArgs());
}
private void OnFrobbed() …Run Code Online (Sandbox Code Playgroud)