10

受け渡し、比較、認識が可能な名前付きメンバーを持つ不変の匿名型、つまりタプルと匿名型のマージが必要です。これは存在しません、そして私はそれを理解しています。

質問は次のとおりです。C#4 または 5 を使用して、これに代わる適切な慣用句は何ですか?

ユース ケースは、異種データ ソースからの流動的な LINQ データ処理です​​。つまり、C# の ETL です。私はかなり複雑な分析を行っており、データは複数のプラットフォームとソースから取得されています。「すべてを同じプラットフォームに置いて、Entity Framework を使用する」という選択肢はありません。本質的に任意のレコード(読み取り専用プロパティの不変の名前付きセット)を流動的に受け渡しできるようにしたいと考えています。

それ以外の場合は匿名の型ごとにカスタムの不変 POCO を作成する以外に思いつくことができる唯一のことは、属性を使用して、Tuples を返すメソッドにコンパイル済みの注釈を追加することです。確かに、不変の POCO を吐き出すためのコード ジェネレーターを作成するのは難しくありませんが、それによってプロジェクトのオブジェクト モデルが乱雑になるのは嫌です。を使用dynamicすると、静的型付けのすべてのパフォーマンスと設計時の有用性が完全に失われます。特に、他のメソッドの結果からさらにクエリを作成する場合はそうです。したがって、実行可能な解決策とは考えていません。

// My idea: Adding a attribute to methods to at least record the names
// of the "columns" of a Tuple at a method level
public class NamedTupleAttribute : Attribute {
    public string[] Names { get; private set; }
    public NamedTupleAttribute(string[] Names) { this.Names = Names; }
}

// Using NamedTuple attribute to note meaning of members of Tuple
[NamedTuple(new[] { "StoreNumber", "Gross", "Cost", "Tax" })]
public IEnumerable<Tuple<int, decimal, decimal, decimal>> GetSales { ... }

私が欲しいもの (C# 6 の架空の MSDN ドキュメント):

アヒル (C# リファレンス)

ダックキーワードを使用すると、C# の静的に型指定されたすべての機能で匿名型を使用できます。通常の匿名型と同様に、コンパイラは、プロパティの数、名前、および型が同じ匿名型を同じ型として扱います。ただし、duck キーワードを使用すると、これらの型をメンバー宣言で使用したり、ジェネリック型の型パラメーターとして使用したりすることもできます。

1. アヒル型のインスタンス

匿名型と同様に、ダック型オブジェクトのインスタンスは、型名なしでオブジェクト初期化子を使用してのみ作成できます。構文は通常の匿名型と同じですが 、 new演算子の後にキーワードダックが追加されます。

var record = new duck { StoreNumber=1204,
                        Transaction=410, 
                        Date=new DateTime(2012, 12, 13), 
                        Gross=135.12m, 
                        Cost=97.80m,
                        Tax=12.11m };

2. アヒル型参照

ダック型は、ダック型リテラル、ダック型エイリアスを使用して参照するか、プロパティまたはメソッドの戻り値の型を推測できる場合は暗黙的に参照できます。

2.1 ダック型リテラル

ダック型は、型参照の代わりに使用できる型リテラルで表現できます。Duck 型リテラルは、中かっこで囲まれていることを除いて、メソッドのパラメーター リストと同様に、duckキーワードの後に​​名前と型識別子のペアのリストが続きます。

// A duck type literal:
duck { int StoreNumber, int Transaction, DateTime Date, decimal Gross, decimal Cost, decimal Tax }

// In a member declaration:
public duck { int StoreNumber, int Transaction, DateTime Date, 
              decimal Gross, decimal Cost, decimal Tax } GetTransaction(...) { ... }

// As a type parameter:
var transactions = new List<duck { int StoreNumber, int Transaction, DateTime Date, 
                                   decimal Gross, decimal Cost, decimal Tax }>();
2.2 ダック型エイリアス

C# コード ファイルまたは名前空間の名前空間 using ディレクティブの直後に using ディレクティブを使用して、ダック型にエイリアスを割り当てることができます。エイリアスは、任意の型参照の代わりに使用できます。

// Namespace directives:
using System;
using Odbc = System.Data.Odbc;

// duck type aliases:
using TransTotal = duck { int StoreNumber, int Transaction, DateTime Date, 
                           decimal Gross, decimal Cost, decimal Tax };

// Member declaration:
public TransTotal GetTransaction(...) { ... }

// As a type parameter:
var transactions = new List<TransTotal>();
2.3 推測されるアヒルの型

プロパティまたはメソッドの戻り値の型を推測できる場合、ダック型リテラルの本体はメンバー宣言で省略できます。

// Long form:
public duck { int StoreNumber, int Transaction, DateTime Date, 
              decimal Gross, decimal Cost, decimal Tax } GetDummyTransaction() {
    return new duck { ... };
}

// Short form:
public duck GetDummyTransaction() {
    return new duck { ... };
}

// Short form as a type parameter:
public IEnumerabe<duck> GetTransactions(...) {
    return 
        from record in someProvider.GetDetails(...)
        where ((DateTime)record["Date"]).Date == someDate
        group record by new {
            StoreNumber = (int)record["Number"],
            Transaction = (int)record["TransNum"],
            Date = (DateTime)record["Date"]
        } into transTotal
        select new duck {
            transTotal.Key.StoreNumber,
            transTotal.Key.Transaction,
            transTotal.Key.Date,
            Gross = transTotal.Sum(x => (decimal)x["Gross"]),
            Cost = transTotal.Sum(x => (decimal)x["Cost"]),
            Tax = transTotal.Sum(x => (decimal)x["Tax"]),
        };
}
4

4 に答える 4

6

ExpandoObjectはあなたの興味を引くかもしれません。

于 2012-10-22T16:31:02.747 に答える
1

独自の IDynamicObjectProvider を実装したいようです: http://msdn.microsoft.com/en-us/library/system.dynamic.idynamicmetaobjectprovider.aspx

実装例: http://msdn.microsoft.com/en-us/vstudio/ff800651.aspx

String が名前、Type が値の型、Object が値である List> のような構造にアクセスしたいようです。

しかし、それは大きな面倒のように思えますし、おそらくあまり良いパフォーマンスを提供しないでしょう. おそらく、必要なすべての適切なクラスを実装する必要があります。あなたの後にコードを保守しなければならない人の正気を保つために、入力ごとにインターフェースを定義することは合理的なように思えます。

于 2012-10-22T18:04:35.313 に答える
1

このアプローチを見たいと思うかもしれません:

public IEnumerable<T> GetTransactions<T>(..., 
    Func<int, int, DateTime, decimal, decimal, decimal, T> resultor) {
    return 
        from record in someProvider.GetDetails(...)
        where ((DateTime)record["Date"]).Date == someDate
        group record by new {
            StoreNumber = (int)record["Number"],
            Transaction = (int)record["TransNum"],
            Date = (DateTime)record["Date"]
        } into transTotal
        select resultor(
            transTotal.Key.StoreNumber,
            transTotal.Key.Transaction,
            transTotal.Key.Date,
            transTotal.Sum(x => (decimal)x["Gross"]),
            transTotal.Sum(x => (decimal)x["Cost"]),
            transTotal.Sum(x => (decimal)x["Tax"])
        );
}

これresultor Funcは、concrete のレイアウトにマップされ、duck同じ数のパラメーターを取り、型が一致し、 を返しますT。これTは、メソッド ad を呼び出して具体的なものを提供すると、次のように推測されます。Funcたとえば、次のようになります。

GetTransactions(..., (sn, t, d, g, c, tx) => return new {
    StoreNumber = sn,
    Transaction = t,
    Date        = d,
    Gross       = g,
    Cost        = c,
    Tax         = tx
});

このようにして、生成された型は呼び出されたメソッドの外部で使用できます。これは、呼び出し元に定義の責任を与えるためです。POCO DTO、動的、不変性、すぐに使える平等はありません。見てみな。

于 2012-10-22T18:44:09.457 に答える
0

ダイナミックが遅すぎると確信していますか? 動的操作と直接呼び出しのパフォーマンス テストを行ったことがありますが、実際、動的呼び出しによる影響がほとんどないことに驚きました。私は自分の数字を持っていませんが、この小さなブログ投稿を見つけましたが、操作の長さが約 10 倍しか増加していないことを示しています。彼の例では、200 万回の呼び出しに 85 ミリ秒かかっているのに対し、静的な呼び出しでは 7 ミリ秒かかることが示されています。

それは合計します。6 秒の操作には 1 分かかりますが、純粋な反射を処理するよりもはるかに短い時間です。

于 2012-10-22T19:46:45.643 に答える