在 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;
}

在 LINQ 语句的调用中使用变量是否安全?

这将起作用 - 前提是您实际完全评估了查询。

但是,这种行为会非常奇怪,并且是我强烈避免的。 由于 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);
}

对于更复杂的方案,具有合理命名属性的类型会更好。