首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用反射将IEnumerable<T>复制到IList<T>的更好解决方案

使用反射将IEnumerable<T>复制到IList<T>的更好解决方案
EN

Stack Overflow用户
提问于 2022-10-31 18:09:45
回答 2查看 64关注 0票数 0

我提供了一个多管乐器来展示这个问题。

我尝试从具有相同属性名称和类型的源复制对象,除了一些具有IEnumerable和目标对象具有使用反射的IList的属性之外。

代码语言:javascript
运行
复制
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[]

我试着皈依:

代码语言:javascript
运行
复制
    var sourceValue = Convert.ChangeType(property.GetValue(src, null), pi.PropertyType);

但同时也有错误

System.InvalidCastException: Object must implement IConvertible.

这个问题帮不上忙。

我的解决方案是铸造:

代码语言:javascript
运行
复制
    sourceValue = ((IEnumerable<string>) sourceValue).Cast<string>().ToList();

缺点是很难将转换连接到IEnumerable<string>

是否有更好的方法使用反射复制IEnumerable<T> to IList<T>或任何泛型集合。

EN

回答 2

Stack Overflow用户

发布于 2022-10-31 19:36:19

一种简单的方法是检查IEnumerable<T>是否可以从源属性的类型中分配,检查目标属性的类型是否可以从List<T>分配,如果可以,则将一个新的List<T>分配给将源属性的值传递给构造函数的目标属性。

代码语言:javascript
运行
复制
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>,即使两个对象上的属性都是完全相同的类型。还不清楚这是否是您想要的,但它与此方法复制其他属性的方式不同,因此值得一提。

票数 1
EN

Stack Overflow用户

发布于 2022-10-31 19:02:55

我认为您也需要添加目标类型的检查。

然后,使用两种不同的类型(源类型和目标类型),您可以创建一个函数来处理转换/强制转换。

就像这样:

代码语言:javascript
运行
复制
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?
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74267482

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档