将匿名类型转换为新的 C# 7 元组类型
Convert anonymous type to new C# 7 tuple type
新版本的 C# 已推出,具有有用的新功能元组类型:
public IQueryable<T> Query<T>();
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.Select(o => new {
id = o.Id,
name = o.Name,
})
.First();
return (id: obj.id, name: obj.name);
}
有没有一种方法可以将我的匿名类型对象 obj 转换为我想要 return 的元组,而无需通过 属性 映射 属性(假设属性名称匹配)?
上下文在 ORM 中,我的 SomeType 对象有很多其他属性,它映射到一个 table 有很多列。我想做一个只带 ID 和 NAME 的查询,所以我需要将匿名类型转换成一个元组,或者我需要一个 ORM Linq Provider 知道如何理解一个元组并将属性相关的列放在 SQL select 条款。
当然,通过从 LINQ 表达式创建元组:
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.Select(o => (o.Id,o.Name))
.First();
return obj;
}
根据 to another answer 关于 C# 7 之前的元组,您可以使用 AsEnumerable()
来防止 EF 混淆。 (我对 EF 的经验不多,但这应该可以:)
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.AsEnumerable()
.Select(o => (o.Id,o.Name))
.First();
return obj;
}
简短的回答是否定的,在 C#7 的当前形式中,没有框架内的方式来逐字完成您的目标,因为您想要完成:
- Linq-to-entities
- 映射到列的子集
- 通过 属性 通过直接映射到 C#7 元组来避免 属性 从自定义或匿名类型映射到 C#7 元组。
因为 Query<SomeType>
公开了 IQueryable
,所以必须对表达式树 .Select(x => new {})
进行任何类型的投影。
有一个 open roslyn issue 用于添加此支持,但目前还不存在。
因此,在添加此支持之前,您可以手动从匿名类型映射到元组,或者 return 整个记录并将结果直接映射到元组以避免两次映射,但这显然是低效的。
虽然由于缺乏支持以及无法在 .Select()
投影中使用参数化构造函数,此限制目前已纳入 Linq-to-Entities,但 Linq-to-NHibernate 和 Linq-to- Sql 允许以在 .Select()
投影中创建新 System.Tuple
的形式进行黑客攻击,然后使用 .ToValueTuple() 扩展方法 returning ValueTuple:
public IQueryable<T> Query<T>();
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.Select(o => new System.Tuple<int, string>(o.Id, o.Name))
.First();
return obj.ToValueTuple();
}
由于 System.Tuple 可以映射到表达式,您可以 return 来自 table 的数据子集,并允许框架处理到 C#7 元组的映射。然后,您可以使用您选择的任何命名约定来解构参数:
(int id, string customName) info = GetSomeInfo();
Console.Write(info.customName);
虽然表达式树目前不支持元组文字,但这并不意味着 ValueTuple
类型不支持。只需显式创建即可。
public (int id, string name) GetSomeInfo() =>
Query<SomeType>()
.Select(o => ValueTuple.Create(o.Id, o.Name))
.First();
public IList<(int DictionaryId, string CompanyId)> All(string DictionaryType)
{
var result = testEntities.dictionary.Where(p => p.Catalog == DictionaryType).ToList();
var resultTuple = result.Select(p => (DictionaryId: p.ID, CompanyId: p.CompanyId));
return resultTuple.ToList();
}
您可以使用此方法在 linq 中命名您的元组项 select
使用较低版本 .NET 的任何人请注意:
如果您使用的 .NET 版本低于 4.7.2 或 .NET Core,您应该使用 Nuget 包管理器将 System.ValueTuple 安装到您的项目。
然后,这是从 Linq 到 SQL 查询获取元组的示例:
var myListOfTuples = (from record1 in myTable.Query()
join record2 in myTable2.Query() on record1.Id = record2.someForeignKey
select new {record1, record2}).AsEnumerable()
.select(o => (o.record1, o.record2))
.ToList()
对我来说 运行,但是,在 check-in 之后,我遇到了构建失败...请继续阅读。
为了获得更多乐趣和游戏,不幸的是,出于某种原因,我的构建服务器上安装了早期版本的 C#。所以我不得不回去,因为它无法识别 .select(o => (o.record1, o.record2)) 行上的新元组格式(特别是它会是一个元组,因为o.record1 和 o.record2 周围的括号)。所以,我不得不回去再多弄点花招:
var myListOfAnonymousObjects = (from record1 in myTable.Query()
join record2 in myTable2.Query() on record1.Id = record2.someForeignKey
select new {record1, record2}).ToList()
var myTuples = new List<Tuple<Record1sClass, Record2sClass>>();
foreach (var pair in myListOfAnonymousObjects)
{
myTuples.Add(pair.record1, pair.record2);
}
return myTuples;
新版本的 C# 已推出,具有有用的新功能元组类型:
public IQueryable<T> Query<T>();
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.Select(o => new {
id = o.Id,
name = o.Name,
})
.First();
return (id: obj.id, name: obj.name);
}
有没有一种方法可以将我的匿名类型对象 obj 转换为我想要 return 的元组,而无需通过 属性 映射 属性(假设属性名称匹配)?
上下文在 ORM 中,我的 SomeType 对象有很多其他属性,它映射到一个 table 有很多列。我想做一个只带 ID 和 NAME 的查询,所以我需要将匿名类型转换成一个元组,或者我需要一个 ORM Linq Provider 知道如何理解一个元组并将属性相关的列放在 SQL select 条款。
当然,通过从 LINQ 表达式创建元组:
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.Select(o => (o.Id,o.Name))
.First();
return obj;
}
根据 to another answer 关于 C# 7 之前的元组,您可以使用 AsEnumerable()
来防止 EF 混淆。 (我对 EF 的经验不多,但这应该可以:)
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.AsEnumerable()
.Select(o => (o.Id,o.Name))
.First();
return obj;
}
简短的回答是否定的,在 C#7 的当前形式中,没有框架内的方式来逐字完成您的目标,因为您想要完成:
- Linq-to-entities
- 映射到列的子集
- 通过 属性 通过直接映射到 C#7 元组来避免 属性 从自定义或匿名类型映射到 C#7 元组。
因为 Query<SomeType>
公开了 IQueryable
,所以必须对表达式树 .Select(x => new {})
进行任何类型的投影。
有一个 open roslyn issue 用于添加此支持,但目前还不存在。
因此,在添加此支持之前,您可以手动从匿名类型映射到元组,或者 return 整个记录并将结果直接映射到元组以避免两次映射,但这显然是低效的。
虽然由于缺乏支持以及无法在 .Select()
投影中使用参数化构造函数,此限制目前已纳入 Linq-to-Entities,但 Linq-to-NHibernate 和 Linq-to- Sql 允许以在 .Select()
投影中创建新 System.Tuple
的形式进行黑客攻击,然后使用 .ToValueTuple() 扩展方法 returning ValueTuple:
public IQueryable<T> Query<T>();
public (int id, string name) GetSomeInfo() {
var obj = Query<SomeType>()
.Select(o => new System.Tuple<int, string>(o.Id, o.Name))
.First();
return obj.ToValueTuple();
}
由于 System.Tuple 可以映射到表达式,您可以 return 来自 table 的数据子集,并允许框架处理到 C#7 元组的映射。然后,您可以使用您选择的任何命名约定来解构参数:
(int id, string customName) info = GetSomeInfo();
Console.Write(info.customName);
虽然表达式树目前不支持元组文字,但这并不意味着 ValueTuple
类型不支持。只需显式创建即可。
public (int id, string name) GetSomeInfo() =>
Query<SomeType>()
.Select(o => ValueTuple.Create(o.Id, o.Name))
.First();
public IList<(int DictionaryId, string CompanyId)> All(string DictionaryType)
{
var result = testEntities.dictionary.Where(p => p.Catalog == DictionaryType).ToList();
var resultTuple = result.Select(p => (DictionaryId: p.ID, CompanyId: p.CompanyId));
return resultTuple.ToList();
}
您可以使用此方法在 linq 中命名您的元组项 select
使用较低版本 .NET 的任何人请注意: 如果您使用的 .NET 版本低于 4.7.2 或 .NET Core,您应该使用 Nuget 包管理器将 System.ValueTuple 安装到您的项目。
然后,这是从 Linq 到 SQL 查询获取元组的示例:
var myListOfTuples = (from record1 in myTable.Query()
join record2 in myTable2.Query() on record1.Id = record2.someForeignKey
select new {record1, record2}).AsEnumerable()
.select(o => (o.record1, o.record2))
.ToList()
对我来说 运行,但是,在 check-in 之后,我遇到了构建失败...请继续阅读。
为了获得更多乐趣和游戏,不幸的是,出于某种原因,我的构建服务器上安装了早期版本的 C#。所以我不得不回去,因为它无法识别 .select(o => (o.record1, o.record2)) 行上的新元组格式(特别是它会是一个元组,因为o.record1 和 o.record2 周围的括号)。所以,我不得不回去再多弄点花招:
var myListOfAnonymousObjects = (from record1 in myTable.Query()
join record2 in myTable2.Query() on record1.Id = record2.someForeignKey
select new {record1, record2}).ToList()
var myTuples = new List<Tuple<Record1sClass, Record2sClass>>();
foreach (var pair in myListOfAnonymousObjects)
{
myTuples.Add(pair.record1, pair.record2);
}
return myTuples;