C# 在LINQ语句内的调用中使用out变量安全吗?
我以前从未这样做过,虽然我想不出它会崩溃的具体原因,但我想验证一下使用out变量是否有效,如下所示:C# 在LINQ语句内的调用中使用out变量安全吗?,c#,linq,C#,Linq,我以前从未这样做过,虽然我想不出它会崩溃的具体原因,但我想验证一下使用out变量是否有效,如下所示: void Main() { var types = new [] { typeof(A), typeof(B) }; bool b = false; var q = from type in types from property in type.GetProperties() let propertyName = GetN
void Main()
{
var types = new [] { typeof(A), typeof(B) };
bool b = false;
var q = from type in types
from property in type.GetProperties()
let propertyName = GetName(property, out b)
select new {
TypeName = type.Name,
PropertyName = propertyName,
PropertyType = property.PropertyType.Name,
IsNullable = b
};
q.Dump();
}
private string GetName(PropertyInfo property, out bool isNullable)
{
string typeName;
isNullable = false;
var type = property.PropertyType;
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
isNullable = true;
typeName = type.GetGenericArguments().First().Name;
}
else
{
typeName = property.Name;
}
return typeName;
}
如果您确实对查询进行了完整的评估,这将起作用 然而,这种行为会非常奇怪,我会极力避免。由于out参数直接在查询中使用,因此如果您不做任何其他操作,那么这里的行为将相当正常,但这是特定于此用例的,而不是将out与LINQ混合使用的一般规则 问题是LINQ的延迟执行将导致设置out参数,但只有在使用结果可枚举时,而不是在声明它时。这可能会导致非常意外的行为,并导致难以维护和理解软件 我个人只需编写一个单独的方法,并使用它将您的查询编写为:
var q = from type in types
from property in type.GetProperties()
let propertyName = GetName(property)
let nullable = GetIsNullable(property)
// ...
这一点更加明确,也不太容易出错。如果以后有人试图改变这一点,它还将与并行化(即PLINQ via.AsParallel)和其他技术一起工作 从语义上讲,这样做是合法的,但它是否安全取决于你如何做。这里最基本的危险是,您正在将局部变量的赋值与延迟(可能永远不会执行)的表达式相结合 在这种情况下,如果集合为空,则对GetName的调用实际上可能永远不会发生。因此,它可能始终保持其原始值false,这也是C编译器强制您在此处声明默认值的原因。如果这个语义与您的程序一致,那么不使用b是完全正确的。事实上,这似乎是在这种情况下,因为b仅在调用方法后使用 然而,这是我通常会避免的事情。这很容易出错,只会在极端情况下失败。这会起作用,但由于各种错误的原因,这是一种坏习惯,因为在更一般的情况下,这是不安全的。更安全的方法是使用元组:
let info = GetInfo(property)
select new {
TypeName = type.Name,
PropertyName = info.Item1,
PropertyType = property.PropertyType.Name,
IsNullable = info.Item2
};
....
private Tuple<string,bool> GetInfo(PropertyInfo property)
{
string typeName;
bool isNullable = false;
...
return Tuple.Create(typeName, isNullable);
}
对于更复杂的场景,具有合理命名属性的类型会更好。这将被视为最糟糕的做法。@asawyer,你为什么这么说?@asawyer,与什么相反?我正在键入一个响应,但我看到里德很好地覆盖了它。对于任何可能导致并发计算的问题,例如并行计算,都有一个巨大的警告,因为b是共享的。@MarcGravel肯定-我编辑了一个替代方案,显示了一个不会因为这个原因出现这些问题的方案。嗨,我同意投票多数的意见,但我想告诉你,我非常喜欢你的解决方案,因为它避开了导致我在第一个阶段求助于out var的问题place@Aaron没问题;2个选项总比1个好: