我希望具有命名成员的不可变匿名类型能够被传递、比较和识别--元组和匿名类型的合并。这根本不存在,我意识到这一点。
所以问题是:使用C#4还是5?是一个很好的习语替代物。
用例是来自异构数据源的流体LINQ数据处理。总之,C#中的ETL。我做了一些非常复杂的分析,数据来自多个平台和来源。它不是一个选项,“只是把它放在同一个平台上,并使用实体框架”。我希望能够流畅地传递本质上是任意记录的内容--不可变的名为只读属性集。
除了为每一个匿名类型创建一个自定义不可变的POCO之外,我唯一能想到的就是使用属性向返回Tuple的方法添加编译后的注释。当然,编写一个代码生成器来吐出不可变的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#的所有静态类型特性中使用匿名类型。与普通的匿名类型一样,编译器将使用相同的数字、名称和属性类型的匿名类型视为具有相同类型。但是,鸭子关键字还允许在成员声明中使用这些类型,并将其用作泛型类型的类型参数。
1.鸭子类型实例
与匿名类型一样,只能使用没有类型名称的对象初始化器创建鸭子类型对象的实例。语法与普通匿名类型相同,只是在新运算符之后添加了关键字:
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鸭子类型文字
可以用类型文字来表示鸭子类型,它可以用于任何类型引用的位置。除大括号外,鸭子类型文本由关键字后面的名称类型标识符对列表组成,与方法的参数列表一样:
// 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指令为鸭子类型分配别名。然后,可以在任何类型引用的位置使用别名。
// 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"]),
};
}发布于 2012-10-22 16:31:02
ExpandoObject可能是你感兴趣的。
发布于 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是值。
但这似乎是一个很大的麻烦,可能不会提供很好的表现。您可能应该实现所需的所有适当类。对于那些必须在您之后维护代码的人来说,为每个输入定义接口似乎是合理的。
发布于 2012-10-22 18:44:09
您可能想看看这种方法:
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,例如:
GetTransactions(..., (sn, t, d, g, c, tx) => return new {
StoreNumber = sn,
Transaction = t,
Date = d,
Gross = g,
Cost = c,
Tax = tx
});这样,生成的类型就可以在被调用的方法之外使用,因为您将定义它的责任交给了调用方。没有POCO DTO,没有动态的,不变的,平等的。看看这个。
https://stackoverflow.com/questions/13015520
复制相似问题