C# FOREACH 在多个列表<>类型上
本文关键字:类型 列表 FOREACH | 更新日期: 2023-09-27 18:31:45
大家好,感谢您的观看。
我认为这是不可能的,但我想通过多个返回的 LIST<> 类型执行相同的 FOREACH,而无需剪切和粘贴代码 4 次。 返回的 dto2、dto3、dto4 和 dto5 列表的所有属性都是相同的,但 DataValue 除外,每个列表的数据类型不同(int、varchar、bool 等)。
var dto2 = rd.EngDetailBitsList(dto.EngId);
var dto3 = rd.EngDetailDateTimesList(dto.EngId);
var dto4 = rd.EngDetailVarCharsList(dto.EngId);
var dto5 = rd.EngDetailVarCharMaxesList(dto.EngId);
foreach (var x in dto2)
{
var propertyInfo = dto.GetType().GetProperty(x.ShortDescript,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
if (propertyInfo != null)
{
propertyInfo.SetValue(dto, x.DataValue);
}
}
foreach (var x in dto3)
{
var propertyInfo = dto.GetType().GetProperty(x.ShortDescript,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
if (propertyInfo != null)
{
propertyInfo.SetValue(dto, x.DataValue);
}
}
foreach (var x in dto4)
{
var propertyInfo = dto.GetType().GetProperty(x.ShortDescript,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
if (propertyInfo != null)
{
propertyInfo.SetValue(dto, x.DataValue);
}
}
foreach (var x in dto5)
{
var propertyInfo = dto.GetType().GetProperty(x.ShortDescript,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
if (propertyInfo != null)
{
propertyInfo.SetValue(dto, x.DataValue);
}
}
有两种方法可以解决这个问题:
-
假设所有
dto2
、dto3
、dto4
和dto5
都是某种类型T
的集合,这些集合实现了与其上声明的ShortDescript
和DataValue
属性的公共接口。var dto2 = rd.EngDetailBitsList(dto.EngId); var dto3 = rd.EngDetailDateTimesList(dto.EngId); var dto4 = rd.EngDetailVarCharsList(dto.EngId); var dto5 = rd.EngDetailVarCharMaxesList(dto.EngId); var source = dto2.Cast<MyInterface> .Concat(dto3.Cast<MyInterface>) .Concat(dto4.Cast<MyInterface>) .Concat(dto4.Cast<MyInterface>); var dtoType = dto.GetType(); foreach (var x in source) { var propertyInfo = dtoType.GetProperty(x.ShortDescript, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase); if (propertyInfo != null) { propertyInfo.SetValue(dto, x.DataValue); } }
-
如果没有通用接口,您可以使用
dynamic
:var dto2 = rd.EngDetailBitsList(dto.EngId); var dto3 = rd.EngDetailDateTimesList(dto.EngId); var dto4 = rd.EngDetailVarCharsList(dto.EngId); var dto5 = rd.EngDetailVarCharMaxesList(dto.EngId); var source = dto2.Cast<dynamic> .Concat(dto3.Cast<dynamic>) .Concat(dto4.Cast<dynamic>) .Concat(dto4.Cast<dynamic>); dto.GetType() foreach (var x in source) { var propertyInfo = dtoType.GetProperty(x.ShortDescript, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase); if (propertyInfo != null) { propertyInfo.SetValue(dto, x.DataValue); } }
这将使
ShortDescript
和DataValue
属性在运行时解析,当实际类型上没有此类属性时,你将获得异常。
如果你想要一个全反射解决方案,你可以做一个这样的方法:
static void SetDtoFields<T>(object targetDto, IEnumerable<T> fields)
{
Type fieldType = typeof(T);
var fieldNameProp = fieldType.GetProperty("ShortDescript");
if (fieldNameProp == null || !fieldNameProp.CanRead)
return;
var dataValProp = fieldType.GetProperty("DataValue");
if (dataValProp == null || !dataValProp.CanRead)
return;
Type targetType = targetDto.GetType();
foreach (T field in fields)
{
var propToSet = targetType.GetProperty((string)fieldNameProp.GetValue(field),
BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase );
if (propToSet != null && propToSet.CanWrite &&
propToSet.PropertyType.IsAssignableFrom(dataValProp.PropertyType))
{
propToSet.SetValue(targetDto, dataValProp.GetValue(field));
}
}
}
然后在您的主代码中,您可以简单地执行以下操作:
SetDtoFields(dto, rd.EngDetailBitsList(dto.EngId));
SetDtoFields(dto, rd.EngDetailDateTimesList(dto.EngId));
SetDtoFields(dto, rd.EngDetailVarCharsList(dto.EngId));
SetDtoFields(dto, rd.EngDetailVarCharMaxesList(dto.EngId));
这是一个工作演示:https://dotnetfiddle.net/GhrJ0f
我会尝试这样的事情。对于您的 dto2,dto3,dto4,dto5 类,请让它们共享此接口:
public interface IDto
{
string ShortDescript {get;set;}
object ObjectValue {get;}
}
在对象上实现 ObjectValue(以一个为例):
public partial class DetailBits // dto2 class maybe?
{
public object ObjectValue
{
get
{
return DataValue;
}
}
}
然后,创建此函数:
public static void SetValues(DTO dto, IEnumerable<IDto> items)
{
foreach (var x in items)
{
var propertyInfo = dto.GetType().GetProperty(x.ShortDescript,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
if (propertyInfo != null)
{
propertyInfo.SetValue(dto, x.ObjectValue);
}
}
}
最后,您可以在主函数中执行此操作:
var dto2 = rd.EngDetailBitsList(dto.EngId).Cast<IDto>();
var dto3 = rd.EngDetailDateTimesList(dto.EngId).Cast<IDto>();
var dto4 = rd.EngDetailVarCharsList(dto.EngId).Cast<IDto>();
var dto5 = rd.EngDetailVarCharMaxesList(dto.EngId).Cast<IDto>();
SetValues(dto, dto2);
SetValues(dto, dto3);
SetValues(dto, dto4);
SetValues(dto, dto5);
我使用了Martin的#2动态投射解决方案,并进行了一些编辑更改。 效果真棒!
var dto2 = rd.EngDetailBitsList(dto.EngId);
var dto3 = rd.EngDetailDateTimesList(dto.EngId);
var dto4 = rd.EngDetailVarCharsList(dto.EngId);
var dto5 = rd.EngDetailVarCharMaxesList(dto.EngId);
var source = dto2.Concat(dto3.Concat(dto4.Concat(dto5.Cast<dynamic>())));
var dtoType = dto.GetType();
foreach (var x in source)
{
var propertyInfo = dtoType.GetProperty(x.ShortDescript,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
if (propertyInfo != null)
{
propertyInfo.SetValue(dto, x.DataValue);
}
}
你可以试试这个,它所做的只是获取和设置你的 DTO 对象、集合和属性名称。
var dto2 = rd.EngDetailBitsList(dto.EngId);
var dto3 = rd.EngDetailDateTimesList(dto.EngId);
var dto4 = rd.EngDetailVarCharsList(dto.EngId);
var dto5 = rd.EngDetailVarCharMaxesList(dto.EngId);
ObjectSetter(new object() /* test only */, dto2, "DataValue");
private void ObjectSetter(object dto, string dtoProp,
IEnumerable items, string itemProperty)
{
foreach (var item in items)
{
var propertyInfo = item.GetType().GetProperty(dtoProp,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
var itemValue = dto.GetType().GetProperty(itemProperty,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
if (propertyInfo != null)
{
propertyInfo.SetValue(item, itemValue.GetValue(dto));
}
}
}
您可以通过执行异步处理来提高其性能。
Task.Factory.StartNew(delegate()
{
ObjectSetter(new object() /* test only */, dto2, "DataValue");
});
Task.Factory.StartNew(delegate()
{
ObjectSetter(new object() /* test only */, dto3, "DataValue");
});
Task.Factory.StartNew(delegate()
{
ObjectSetter(new object() /* test only */, dto4, "DataValue");
});
Task.Factory.StartNew(delegate()
{
ObjectSetter(new object() /* test only */, dto5, "DataValue");
});