带有名称的元组的C#解决方法

Jos*_*nig 10 c# linq tuples anonymous-types

我希望不可变的匿名类型具有可以传递,比较和识别的命名成员 - 元组和匿名类型的合并.这不存在,我意识到这一点.

所以问题是:使用C#4或5,这是一个很好的惯用替代品吗?

用例是来自异构数据源的流畅的LINQ数据处理.总之,C#中的ETL.我做了一些非常复杂的分析,数据来自多个平台和来源.它不是"只需将它们放在同一平台上并使用实体框架"的选项.我希望能够流畅地传递基本上任意的记录 - 不可变命名的只读属性集.

我唯一能想到的就是为每个单独的匿名类型创建一个自定义的不可变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 { ... }
Run Code Online (Sandbox Code Playgroud)

我想要的(C#6的虚构MSDN文档):

duck(C#参考)

关键字允许在C#中所有的静态类型的功能使用匿名类型.与普通的匿名类型一样,编译器会将具有相同数量,名称和属性类型的匿名类型视为具有相同类型.但是,duck关键字还允许在成员声明中使用这些类型,并将其用作泛型类型的类型参数.

鸭子型实例

与匿名类型一样,只能使用没有类型名称的对象初始值设定项创建duck类型对象的实例.除了在new运算符之后添加关键字duck之外,语法与普通匿名类型的语法相同 :

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

2.鸭型参考

Duck类型可以使用duck类型文字,duck类型别名引用,或者在可以推断属性或方法的返回类型时隐式引用.

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 }>();
Run Code Online (Sandbox Code Playgroud) 2.2鸭型别名

您可以在命名空间后使用C#代码文件或命名空间中的指令,使用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>();
Run Code Online (Sandbox Code Playgroud) 2.3推断的鸭子类型

如果可以推断属性或方法的返回类型,则可以在成员声明中省略duck类型文字的主体:

// 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"]),
        };
}
Run Code Online (Sandbox Code Playgroud)

Pau*_*ane 6

您可能会对ExpandoObject感兴趣.