我之前从未这样做过,虽然我想不出它会破坏的具体原因,但我想验证使用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;
}
答案 0 :(得分:10)
这将有效 - 只要您实际完全评估查询。
但是,这种行为会很奇怪,而且我会强烈避免这种行为。由于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()
)和其他技术,如果有人试图稍后改变它。
答案 1 :(得分:3)
这样做在语义上是合法的,但它是否安全非常依赖于你如何做到这一点。这里的根本危险在于,您正在使用延迟(可能永远不会执行)的表达式来组合本地的赋值。
如果集合为空,则在这种情况下实际上永远不会发生对GetName
的调用。因此它可能始终保持它的原始值false
(这也正是C#编译器强制您在此处声明默认值的原因)。如果这个语义对你的程序没问题,那么b
的完全使用是完全没问题的。实际上似乎是在这种情况下,因为b
仅在调用方法后使用。
然而,这是我一般会避免的。很容易弄错,只会在极端情况下失败。
答案 2 :(得分:3)
这会起作用,只是,但是出于每一个错误的原因(并且这是一个不好的习惯,因为它在更一般的情况下是不安全的)。一个更安全的想法将是一个元组:
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);
}
对于更复杂的场景,具有合理命名属性的类型会更好。