首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >名称元组的C#解决方案

名称元组的C#解决方案
EN

Stack Overflow用户
提问于 2012-10-22 16:18:05
回答 4查看 4.1K关注 0票数 10

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

所以问题是:使用C#4还是5?是一个很好的习语替代物。

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

除了为每一个匿名类型创建一个自定义不可变的POCO之外,我唯一能想到的就是使用属性向返回Tuple的方法添加编译后的注释。当然,编写一个代码生成器来吐出不可变的POCO并不难,但我讨厌这会把项目的对象模型搞得一团糟。使用dynamic完全消除了静态类型化的所有性能和设计时的有用性,特别是当从其他方法的结果合成进一步的查询时,所以我认为它不是一个可行的解决方案。

代码语言:javascript
运行
复制
// 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#的所有静态类型特性中使用匿名类型。与普通的匿名类型一样,编译器将使用相同的数字、名称和属性类型的匿名类型视为具有相同类型。但是,鸭子关键字还允许在成员声明中使用这些类型,并将其用作泛型类型的类型参数。

1.鸭子类型实例

与匿名类型一样,只能使用没有类型名称的对象初始化器创建鸭子类型对象的实例。语法与普通匿名类型相同,只是在运算符之后添加了关键字:

代码语言:javascript
运行
复制
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鸭子类型文字

可以用类型文字来表示鸭子类型,它可以用于任何类型引用的位置。除大括号外,鸭子类型文本由关键字后面的名称类型标识符对列表组成,与方法的参数列表一样:

代码语言:javascript
运行
复制
// 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指令为鸭子类型分配别名。然后,可以在任何类型引用的位置使用别名。

代码语言:javascript
运行
复制
// 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推断鸭型

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

代码语言:javascript
运行
复制
// 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"]),
        };
}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-10-22 16:31:02

ExpandoObject可能是你感兴趣的。

票数 6
EN

Stack Overflow用户

发布于 2012-10-22 18:04:35

似乎您希望实现自己的IDynamicObjectProvider:http://msdn.microsoft.com/en-us/library/system.dynamic.idynamicmetaobjectprovider.aspx

示例实现:http://msdn.microsoft.com/en-us/vstudio/ff800651.aspx

您似乎希望访问像List>这样的结构,其中String是名称,Type是值类型,Object是值。

但这似乎是一个很大的麻烦,可能不会提供很好的表现。您可能应该实现所需的所有适当类。对于那些必须在您之后维护代码的人来说,为每个输入定义接口似乎是合理的。

票数 1
EN

Stack Overflow用户

发布于 2012-10-22 18:44:09

您可能想看看这种方法:

代码语言:javascript
运行
复制
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被映射到您的具体duck的布局上,使用与匹配类型相同的参数,并返回一个T。当您调用方法并提供具体的T时,就会推断出这个Func,例如:

代码语言:javascript
运行
复制
GetTransactions(..., (sn, t, d, g, c, tx) => return new {
    StoreNumber = sn,
    Transaction = t,
    Date        = d,
    Gross       = g,
    Cost        = c,
    Tax         = tx
});

这样,生成的类型就可以在被调用的方法之外使用,因为您将定义它的责任交给了调用方。没有POCO DTO,没有动态的,不变的,平等的。看看这个。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13015520

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档