受け渡し、比較、認識が可能な名前付きメンバーを持つ不変の匿名型、つまりタプルと匿名型のマージが必要です。これは存在しません、そして私はそれを理解しています。
質問は次のとおりです。C#4 または 5 を使用して、これに代わる適切な慣用句は何ですか?
ユース ケースは、異種データ ソースからの流動的な LINQ データ処理です。つまり、C# の ETL です。私はかなり複雑な分析を行っており、データは複数のプラットフォームとソースから取得されています。「すべてを同じプラットフォームに置いて、Entity Framework を使用する」という選択肢はありません。本質的に任意のレコード(読み取り専用プロパティの不変の名前付きセット)を流動的に受け渡しできるようにしたいと考えています。
それ以外の場合は匿名の型ごとにカスタムの不変 POCO を作成する以外に思いつくことができる唯一のことは、属性を使用して、Tuple
s を返すメソッドにコンパイル済みの注釈を追加することです。確かに、不変の 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"]),
};
}