在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循环中定义的变量不能在循环外使用: …
我收集了一些角落案例和脑筋急转弯,并且总是希望听到更多.该页面仅涵盖C#语言位和bobs,但我也发现核心.NET的东西也很有趣.例如,这是一个不在页面上,但我觉得不可思议的:
string x = new string(new char[0]);
string y = new string(new char[0]);
Console.WriteLine(object.ReferenceEquals(x, y));
Run Code Online (Sandbox Code Playgroud)
我希望打印False - 毕竟,"new"(带引用类型)总是会创建一个新对象,不是吗?C#和CLI的规范都表明它应该.好吧,不是在这种特殊情况下.它打印True,并在我测试过的每个版本的框架上完成.(我没有在Mono上尝试过,诚然......)
需要明确的是,这只是我正在寻找的那种事情的一个例子 - 我并不是特别想要讨论这种奇怪的事情.(它与正常的字符串实习不同;特别是,当调用构造函数时,通常不会发生字符串实习.)我真的要求类似的奇怪行为.
还有其他宝石潜伏在那里吗?
我有一个C#字符串扩展方法,它应返回IEnumerable<int>字符串中子字符串的所有索引.它完美地用于其预期目的,并返回预期的结果(由我的一个测试证明,虽然不是下面的一个),但另一个单元测试发现它有一个问题:它不能处理空参数.
这是我正在测试的扩展方法:
public static IEnumerable<int> AllIndexesOf(this string str, string searchText)
{
if (searchText == null)
{
throw new ArgumentNullException("searchText");
}
for (int index = 0; ; index += searchText.Length)
{
index = str.IndexOf(searchText, index);
if (index == -1)
break;
yield return index;
}
}
Run Code Online (Sandbox Code Playgroud)
这是标记问题的测试:
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void Extensions_AllIndexesOf_HandlesNullArguments()
{
string test = "a.b.c.d.e";
test.AllIndexesOf(null);
}
Run Code Online (Sandbox Code Playgroud)
当测试针对我的扩展方法运行时,它会失败,标准错误消息表明该方法"没有抛出异常".
这很令人困惑:我已明确传入null函数,但由于某种原因,比较null == null正在返回false.因此,不会抛出异常并且代码会继续.
我已经确认这不是测试的错误:在我的主项目中通过调用Console.WriteLinenull比较if块运行该方法时,控制台上没有显示任何内容,并且catch我添加的任何块都没有捕获到任何异常.而且,使用string.IsNullOrEmpty而不是== null …
我想执行这样的查询
var result = from entry in table
where entry.something == null
select entry;
Run Code Online (Sandbox Code Playgroud)
并得到一个IS NULL生成.
编辑:在前两个答案后,我觉得有必要澄清我正在使用实体框架而不是Linq to SQL.object.Equals()方法似乎不适用于EF.
编辑2:上述查询按预期工作.它正确生成IS NULL.然而,我的生产代码是
value = null;
var result = from entry in table
where entry.something == value
select entry;
Run Code Online (Sandbox Code Playgroud)
并且生成的SQL是something = @p; @p = NULL.似乎EF正确地转换了常量表达式,但是如果涉及变量,它就像正常比较一样处理它.实际上是有道理的.我会结束这个问题
C#或.NET Framework中一些最大的设计缺陷是什么?
示例:没有非可空字符串类型,您必须在从IDataReader获取值时检查DBNull.
似乎在.NET Framework中,覆盖方法时可选参数存在问题.下面代码的输出是:"bbb""aaa".但我期待的输出是:"bbb""bbb".有解决方案.我知道它可以用方法重载解决,但想知道原因.此外,代码在Mono中运行良好.
class Program
{
class AAA
{
public virtual void MyMethod(string s = "aaa")
{
Console.WriteLine(s);
}
public virtual void MyMethod2()
{
MyMethod();
}
}
class BBB : AAA
{
public override void MyMethod(string s = "bbb")
{
base.MyMethod(s);
}
public override void MyMethod2()
{
MyMethod();
}
}
static void Main(string[] args)
{
BBB asd = new BBB();
asd.MyMethod();
asd.MyMethod2();
}
}
Run Code Online (Sandbox Code Playgroud) 我正在开发一个C#项目,直到现在,我已经使用了不可变对象和工厂来确保Foo始终可以比较类型对象的相等性==.
Foo创建后无法更改对象,并且工厂始终为给定的参数集返回相同的对象.这很好用,在整个代码库中我们假设它==始终用于检查相等性.
现在我需要添加一些引入边缘情况的功能,但这并不总是有效.最简单的方法是operator ==为该类型重载,以便项目中的其他代码都不需要更改.但这让我感觉像代码味道:重载operator ==并且Equals不仅仅是看起来很奇怪,而且我习惯于==检查引用相等性的约定,并Equals检查对象的相等性(或任何术语).
这是一个合理的问题,还是我应该继续超载operator ==?
我在这些之间完全感到困惑4.ElapsedMilliseconds(long),ElapsedTicks(long),Elapsed.TotalMilliseconds(double)和Elapsed.Milliseconds(int)之间有什么区别?
我有一个功能
{
Stopwatch sw = new Stopwatch();
sw.Start();
MyTimeConsumingAction();
sw.Stop();
sw.//what?
}
Run Code Online (Sandbox Code Playgroud)
如何从秒表对象的已用属性(以毫秒为单位)获取长时间运行的进程所消耗的正确时间?
编辑:我试过msdn文档,但它没有详细说明..
在这个答案中,https: //stackoverflow.com/a/8649429/1497 Eric Lippert说"我们很有可能在下一版本的C#中解决这个问题;对于开发人员而言,这是一个主要的痛点". foreach循环使用变量.
在下一个版本中,每次运行"foreach"循环时,我们将生成一个新的循环变量,而不是每次都关闭相同的变量.这是一个"突破"的变化,但在绝大多数情况下,"休息"将是修复而不是导致错误.
我无法找到任何表明此更改尚未完成的内容.有没有迹象表明这是foreach循环在C#5中的工作方式?
这是绝对的咆哮.我不敢相信自己的眼睛,我不相信在我之前没有人会发现这个,如果它是C#中的一个真正的错误,所以我把它推出给其他开发者社区告诉我我做错了什么.我确定这个问题会让我说"DOH!" 用我的手掌非常用力地拍打我的头 - 但无论如何......
为了测试,我创建了一个表Test_1,脚本如下:
CREATE TABLE TEST_1 (
COLUMN1 NUMBER(12) NOT NULL,
COLUMN2 VARCHAR2(20),
COLUMN3 NUMBER(12))
TABLESPACE USERS
STORAGE (
INITIAL 64K
MAXEXTENTS UNLIMITED
)
LOGGING;
Run Code Online (Sandbox Code Playgroud)
现在我执行以下代码:
var conn = new OracleConnection("connectionblahblah");
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText =
"insert into Test_1(Column1, Column2, Column3) " +
"values(:Column1, :Column2, :Column3)";
var p = cmd.Parameters;
p.Add("Column1", 1);
p.Add("Column3", null);
p.Add("Column2", "record 1");
cmd.ExecuteNonQuery();
Run Code Online (Sandbox Code Playgroud)
哇!我收到ORA-01722错误 - "无效号码"!但是怎么了? Column1是数字,值为1,所以很好; Column2是一个字符串,Column3是一个可以为空的列,所以不应该造成任何麻烦......
现在请坐下来......这里的问题是,Column3并Column2按照它们被添加到的顺序进行转换OracleParameterCollection.切换它们,并预先!有用! …
c# ×9
.net ×4
foreach ×2
.net-4.0 ×1
.net-4.5 ×1
ado.net ×1
c#-5.0 ×1
comparison ×1
equals ×1
ienumerable ×1
lambda ×1
null ×1
ora-01722 ×1
oracle ×1
overriding ×1
performance ×1
scope ×1
stopwatch ×1