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 経由) やその他の手法でも機能します。

于 2012-05-10T21:50:08.490 に答える
3

これを行うことは意味的には合法ですが、安全かどうかは、その方法に大きく依存します。ここでの根本的な危険は、ローカルの代入を遅延し、おそらく決して実行されない式と組み合わせることです。

GetNameこの場合、コレクションが空の場合、への呼び出しは実際には発生しない可能性があります。したがって、常に元の値を維持できますfalse(これは、C# コンパイラがここで既定値を宣言することを強制する理由でもあります)。このセマンティクスがプログラムで問題ない場合は、の使用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);
}

より複雑なシナリオでは、わかりやすい名前のプロパティを持つ型がさらに適しています。

于 2012-05-10T21:52:32.560 に答える