Linq:使用左连接将具有泛型类型的列表组合成泛型类型
Linq : Combine a list with generic type using left join into a generic type
我创建了一个通用函数来构建平面列表,它需要两个参数,其中一个是项目列表,另一个是 return 类型的 DTO,我已经进行了左连接将项目列表与其他列表组合并获得它们的结果
public async Task<List<TContract>> GetFlatList<TInput, TContract>(List<TInput> items)
where TContract : IOther<TContract>, new() // inherit from IItem
where TInput : IItem
{
var itemIds = items.Select(s => s.ItemId).ToList();
var otherList= await otherService.GetOthers(itemIds).ConfigureAwait(false);
var data = otherList
.GroupJoin(
items,
other=> other.ItemId,
items => items.ItemId,
(other, items) => new { other, items })
.SelectMany(
x => x.items.DefaultIfEmpty(),
(other, items) => new TContract(){
ItemId = other.ItemId,
ItemName = items.ItemName,
// where items has other prop and it doesn't typed it returns null
}).ToList();
return data;
}
public interface IItem
{
int ItemId { get; set; }
}
public interface IOther<TContract> : IItem
{
string ItemName { get; set; }
}
在那种情况下,它可以工作,但我不知道项目列表中出现的类型,只是我知道它们共享 ItemId ,而 DTO returns 中的其他字段与 null ,
我试过 return 它作为匿名类型但在那种情况下加入不起作用,
所以我需要 return DTO 中的新连接数据,无论其中的任何字段,而不使用匿名类型。
注:
全部通过
arguments 也继承自 IItem & IOther
public class Item : IItem
{
public int ItemId { get; set; }
public DateTime CreatedDate { get; set; }
}
public class OtherList
{
public int ItemId { get; set; }
public string UserName { get; set; }
public string ItemName{ get; set; }
public DateTime DateOfBirth { get; set; }
}
我需要的最终结果是:
public class OtherContract: IOther<OtherContract>
{
public int ItemId { get; set; }
public string ItemName { get; set; }
public string UserName { get; set; }
public DateTime DateOfBirth { get; set; }
public DateTime CreatedDate { get; set; }
}
用法
var data = await GetFlatList<Item,OtherContract>(itemList);
@MikeHofer 发布的这个 fiddle 是迄今为止最好的解决方案,希望这对其他人有所帮助。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public class Program
{
public static void Main()
{
var items = new List<Item> {
new Item { ItemId = 2 },
new Item { ItemId = 3 }
};
var result = GetFlatList<Item, OtherContract>(items);
}
public static Task<List<TContract>> GetFlatList<TInput, TContract>(List<TInput> items)
where TContract : IOther<TContract>, new() // inherit from IItem
where TInput : IItem
{
var itemIds = items.Select(s => s.ItemId).ToList();
var otherList = new OtherService().GetOthers(itemIds);
var data = otherList.GroupJoin(
items,
o => o.ItemId, // otherList
i => i.ItemId, // items
(thisOther, thisItem) => new IntermediateResult
{
Other = thisOther,
Item = (IEnumerable<IItem>)thisItem
})
.Where(i => i.Item.Any())
.ToList();
var list = data.SelectMany(
x => x.Item.DefaultIfEmpty(),
(x, item) => GetContract(x)).ToList();
return (Task<List<TContract>>)(object)list;
}
public static OtherContract GetContract(IntermediateResult intermediateResult)
{
return new OtherContract
{
ItemId = intermediateResult.Item.FirstOrDefault().ItemId,
ItemName = ((OtherContract)intermediateResult.Other).ItemName
};
}
public class IntermediateResult
{
public IItem Other { get; set; }
public IEnumerable<IItem> Item { get; set; }
}
public interface IItem
{
int ItemId { get; set; }
}
public interface IOther<TContract> : IItem
{
string ItemName { get; set; }
}
public class Item : IItem
{
public int ItemId { get; set; }
public DateTime CreatedDate { get; set; }
}
public class OtherContract : IOther<OtherContract>
{
public int ItemId { get; set; }
public string ItemName { get; set; }
public string UserName { get; set; }
public DateTime DateOfBirth { get; set; }
public DateTime CreatedDate { get; set; }
}
public class OtherService
{
public IEnumerable<IItem> GetOthers(IEnumerable<int> itemIds)
{
return new List<IItem> {
new OtherContract { ItemId = 1, ItemName = "First" },
new OtherContract { ItemId = 2, ItemName = "Second" },
new OtherContract { ItemId = 3, ItemName = "Third" }
};
}
}
}
我创建了一个通用函数来构建平面列表,它需要两个参数,其中一个是项目列表,另一个是 return 类型的 DTO,我已经进行了左连接将项目列表与其他列表组合并获得它们的结果
public async Task<List<TContract>> GetFlatList<TInput, TContract>(List<TInput> items)
where TContract : IOther<TContract>, new() // inherit from IItem
where TInput : IItem
{
var itemIds = items.Select(s => s.ItemId).ToList();
var otherList= await otherService.GetOthers(itemIds).ConfigureAwait(false);
var data = otherList
.GroupJoin(
items,
other=> other.ItemId,
items => items.ItemId,
(other, items) => new { other, items })
.SelectMany(
x => x.items.DefaultIfEmpty(),
(other, items) => new TContract(){
ItemId = other.ItemId,
ItemName = items.ItemName,
// where items has other prop and it doesn't typed it returns null
}).ToList();
return data;
}
public interface IItem
{
int ItemId { get; set; }
}
public interface IOther<TContract> : IItem
{
string ItemName { get; set; }
}
在那种情况下,它可以工作,但我不知道项目列表中出现的类型,只是我知道它们共享 ItemId ,而 DTO returns 中的其他字段与 null , 我试过 return 它作为匿名类型但在那种情况下加入不起作用, 所以我需要 return DTO 中的新连接数据,无论其中的任何字段,而不使用匿名类型。
注: 全部通过 arguments 也继承自 IItem & IOther
public class Item : IItem
{
public int ItemId { get; set; }
public DateTime CreatedDate { get; set; }
}
public class OtherList
{
public int ItemId { get; set; }
public string UserName { get; set; }
public string ItemName{ get; set; }
public DateTime DateOfBirth { get; set; }
}
我需要的最终结果是:
public class OtherContract: IOther<OtherContract>
{
public int ItemId { get; set; }
public string ItemName { get; set; }
public string UserName { get; set; }
public DateTime DateOfBirth { get; set; }
public DateTime CreatedDate { get; set; }
}
用法
var data = await GetFlatList<Item,OtherContract>(itemList);
@MikeHofer 发布的这个 fiddle 是迄今为止最好的解决方案,希望这对其他人有所帮助。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public class Program
{
public static void Main()
{
var items = new List<Item> {
new Item { ItemId = 2 },
new Item { ItemId = 3 }
};
var result = GetFlatList<Item, OtherContract>(items);
}
public static Task<List<TContract>> GetFlatList<TInput, TContract>(List<TInput> items)
where TContract : IOther<TContract>, new() // inherit from IItem
where TInput : IItem
{
var itemIds = items.Select(s => s.ItemId).ToList();
var otherList = new OtherService().GetOthers(itemIds);
var data = otherList.GroupJoin(
items,
o => o.ItemId, // otherList
i => i.ItemId, // items
(thisOther, thisItem) => new IntermediateResult
{
Other = thisOther,
Item = (IEnumerable<IItem>)thisItem
})
.Where(i => i.Item.Any())
.ToList();
var list = data.SelectMany(
x => x.Item.DefaultIfEmpty(),
(x, item) => GetContract(x)).ToList();
return (Task<List<TContract>>)(object)list;
}
public static OtherContract GetContract(IntermediateResult intermediateResult)
{
return new OtherContract
{
ItemId = intermediateResult.Item.FirstOrDefault().ItemId,
ItemName = ((OtherContract)intermediateResult.Other).ItemName
};
}
public class IntermediateResult
{
public IItem Other { get; set; }
public IEnumerable<IItem> Item { get; set; }
}
public interface IItem
{
int ItemId { get; set; }
}
public interface IOther<TContract> : IItem
{
string ItemName { get; set; }
}
public class Item : IItem
{
public int ItemId { get; set; }
public DateTime CreatedDate { get; set; }
}
public class OtherContract : IOther<OtherContract>
{
public int ItemId { get; set; }
public string ItemName { get; set; }
public string UserName { get; set; }
public DateTime DateOfBirth { get; set; }
public DateTime CreatedDate { get; set; }
}
public class OtherService
{
public IEnumerable<IItem> GetOthers(IEnumerable<int> itemIds)
{
return new List<IItem> {
new OtherContract { ItemId = 1, ItemName = "First" },
new OtherContract { ItemId = 2, ItemName = "Second" },
new OtherContract { ItemId = 3, ItemName = "Third" }
};
}
}
}