我提供了一个多管乐器来展示这个问题。
我尝试从具有相同属性名称和类型的源复制对象,除了一些具有IEnumerable和目标对象具有使用反射的IList的属性之外。
public T CopyTo<T>(object src)
where T : new()
{
var targetObj = new T();
//Getting Type of Src
var sourceType = src.GetType();
BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty;
var sourcePi = sourceType.GetProperties(flags);
foreach (var property in sourcePi)
{
var pi = targetObj.GetType().GetProperty(property.Name);
if (pi == null || !pi.CanWrite)
continue;
object sourceValue = property.GetValue(src, null);
//var sourceValue = Convert.ChangeType(property.GetValue(src, null), pi.PropertyType);
//this works, but hard wired
if (sourceValue is IEnumerable<string> i)
sourceValue = ((IEnumerable<string>)i).Cast<string>().ToList();
pi.SetValue(targetObj, sourceValue, null);
}
return targetObj;
}
它会引发一个错误:
'System.Collections.Generic.List`1System.String'.‘:不能将'System.String[]’类型的对象转换为类型System.String[]
我试着皈依:
var sourceValue = Convert.ChangeType(property.GetValue(src, null), pi.PropertyType);
但同时也有错误
System.InvalidCastException: Object must implement IConvertible.
这个问题帮不上忙。
我的解决方案是铸造:
sourceValue = ((IEnumerable<string>) sourceValue).Cast<string>().ToList();
缺点是很难将转换连接到IEnumerable<string>
是否有更好的方法使用反射复制IEnumerable<T> to IList<T>
或任何泛型集合。
发布于 2022-10-31 19:36:19
一种简单的方法是检查IEnumerable<T>
是否可以从源属性的类型中分配,检查目标属性的类型是否可以从List<T>
分配,如果可以,则将一个新的List<T>
分配给将源属性的值传递给构造函数的目标属性。
public T CopyTo<T>(object src) where T : new()
{
var targetObj = new T();
var sourceType = src.GetType();
BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty;
var sourcePi = sourceType.GetProperties(flags);
foreach (var property in sourcePi)
{
var pi = targetObj.GetType().GetProperty(property.Name);
if (pi == null || !pi.CanWrite)
continue;
object sourceValue = property.GetValue(src, null);
//var sourceValue = Convert.ChangeType(property.GetValue(src, null), pi.PropertyType);
//this works, but hard wired
if (property.PropertyType.IsGenericType)
{
Type enumerable = typeof(IEnumerable<>).MakeGenericType(property.PropertyType.GenericTypeArguments);
if (enumerable.IsAssignableFrom(property.PropertyType))
{
Type list = typeof(List<>).MakeGenericType(property.PropertyType.GenericTypeArguments);
if (pi.PropertyType.IsAssignableFrom(list))
{
var pValue = Activator.CreateInstance(list, new[] { sourceValue });
pi.SetValue(targetObj, pValue, null);
}
}
}
else
{
pi.SetValue(targetObj, sourceValue, null);
}
}
return targetObj;
}
不难想象会有这样的情况.例如,如果目标类型的属性是LinkedList<T>
或T[]
,则属性不会复制。你必须进一步修改它来处理这样的案件。
这还将为目标对象创建一个新的List<T>
,即使两个对象上的属性都是完全相同的类型。还不清楚这是否是您想要的,但它与此方法复制其他属性的方式不同,因此值得一提。
发布于 2022-10-31 19:02:55
我认为您也需要添加目标类型的检查。
然后,使用两种不同的类型(源类型和目标类型),您可以创建一个函数来处理转换/强制转换。
就像这样:
1. Source IEnumerable<T>, Destination: List<T> => Create New list and put in CTOR
2. Source List<T>, Destination: List<T> => Just Copy
3. Source List<T>, Destination: IEnumerable<T> => Create a list
4. Source IEnumerable<T> ,Destination: IEnumerable<T> => Made a copy?
https://stackoverflow.com/questions/74267482
复制相似问题