5

我以前从未这样做过,虽然我想不出它会中断的具体原因,但我想验证使用 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;
}
4

3 回答 3

10

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

但是,这种行为会很奇怪,我会强烈避免。由于在查询中直接使用了 out 参数,因此这里的行为将是相当正常的(前提是您不对此做任何其他事情),但这是特定于这个用例的,而不是使用 out 的一般“规则”与LINQ混合。

问题是 LINQ 的延迟执行将导致设置 out 参数,但仅在您使用生成的可枚举时,而不是在您声明它时。这可能会导致非常意外的行为,并导致难以维护和理解软件。

我个人只是编写一个单独的方法,并使用它来允许您将查询编写为:

var q = from type in types 
        from property in type.GetProperties() 
        let propertyName = GetName(property)
        let nullable = GetIsNullable(property)
        // ...

这更清楚,更不容易出错和错误。.AsParallel()如果有人稍后尝试更改它,它也可以与并行化(即:PLINQ via )和其他技术一起使用。

于 2012-05-10T21:50:08.490 回答
3

这样做在语义上是合法的,但它是否安全在很大程度上取决于你如何做到这一点。这里的基本危险是您将本地的赋值与延迟执行的表达式结合起来,并且可能永远不会执行。

如果集合为空,在这种情况下,调用GetName实际上可能永远不会发生。因此,它可能始终保持其原始值false(这也是 C# 编译器强制您在此处声明默认值的原因)。如果您的程序可以使用此语义,那么 out 的使用b就很好了。实际上,它似乎在这种情况下,因为b仅在调用方法后使用。

但是,这是我通常会避免的事情。很容易出错,以至于它只会在极端情况下失败。

于 2012-05-10T21:52:22.623 回答
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);
}

For more complex scenarios, a type with sensibly named properties would be even better.

于 2012-05-10T21:52:32.560 回答