在 LINQ 语句的调用中使用变量是否安全?
本文关键字:变量 是否 安全 LINQ 语句 调用 | 更新日期: 2023-09-27 18:33:53
我以前从未这样做过,虽然我想不出它会中断的具体原因,但我想验证使用 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 = 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 参数直接在查询中使用,因此此处的行为将相当正常(前提是您不对此执行任何其他操作(,但这是特定于此用例的,而不是与 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);
}
对于更复杂的方案,具有合理命名属性的类型会更好。