使用反射在C#中向未知类型的集合添加元素

3

我正在使用反射来循环遍历一个对象的属性,并将具有相同名称属性的不同对象的值填充。这很好用,但当属性类型为集合时会出现问题。我想能够循环遍历源集合中的每个对象,并使用源集合中的对象填充相同的列表。

public class SourceMessage
{
    public string Name { get; set; }
    public int Version { get; set; }
    public IList<ValueDefinition> Values { get; set; }
}

public class ValueDefinition
{
    public string Name { get; set; }
    public string Value { get; set; }
}

public class TargetObject
{
    public TargetObject()
    {
        Values = new List<TargetValueDefinition>();
    }
    public string Name { get; set; }
    public int Version { get; set; }
    public IList<TargetValueDefinition> Values { get; set; }
}

public class TargetValueDefinition
{
    public string Name { get; set; }
    public string Value { get; set; }
}

然后我使用反射从源对象中填充目标对象。
public static void PopulateFromMessage<T, TS>(ref T targetEntity, TS message)
{
    var sourceType = typeof(TS);
    var targetType = typeof(T);

    foreach (var targetPropInfo in targetType.GetProperties())
    {
        if (sourceType.GetProperty(targetPropInfo.Name) != null)
        {
            var obj = sourceType.GetProperty(targetPropInfo.Name);
            if (obj.PropertyType.Namespace == "System.Collections.Generic")
            {
                //var x = targetType.GetProperty(targetPropInfo.Name);
                //PopulateFromMessage(ref x, sourceType.GetProperty(targetPropInfo.Name));
                continue;
            }
            targetPropInfo.SetValue(targetEntity, sourceType.GetProperty(targetPropInfo.Name).GetValue(message), null);
        }
    }
}

这样调用就像这样:

private void DenormalizeMessage(SourceMessage message)
{
    var newTargetObject = new TargetObject();
    PopulateFromMessage(ref newTargetObject , message);
}

我可以确定属性是一个集合,但不确定如何创建新的TargetValueDefinitions并用ValueDefinitions中的值填充它们。最终,它基本上是SourceMessage的副本,以TargetObject的形式呈现。

所有这些都源于接收消息并将其转换为具有相同属性名称的对象。

3个回答

2
如果您遇到的问题是需要遍历一个包含多个元素的属性集合时,关键在于将属性值读入动态变量而不是默认的对象变量,这样您就可以使用foreach来遍历它。
dynamic propVal = inputProperty.GetValue(item);
foreach (var subItem in propVal)
{    
//do your stuff
}

0

免责声明:这样做极其不安全,且做了很多假设,但它应该能让你走上正确的道路。

将您的方法更改为以下内容:

public static void PopulateFromMessage<T, TS>(T targetEntity, TS message)
    {
        var sourceType = typeof (TS);
        var targetType = typeof (T);

        foreach (var targetPropInfo in targetType.GetProperties())
        {
            if (targetPropInfo.PropertyType.IsGenericType)
            {
                if (targetPropInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>))
                {
                    var originalList = sourceType.GetProperty(targetPropInfo.Name).GetValue(message) as IList;

                    if (originalList != null)
                    {
                        var argumentType = targetPropInfo.PropertyType.GetGenericArguments();
                        var listType = typeof (List<>);
                        var concreteType = listType.MakeGenericType(argumentType);
                        var newList = Activator.CreateInstance(concreteType) as IList;

                        foreach (var original in originalList)
                        {
                            var targetValue = Activator.CreateInstance(argumentType[0]);

                            // do this yourself. Here we're converting ValueDefinition to TargetValueDefinition
                            // targetValue.Fill(original);
                        }

                        targetPropInfo.SetValue(targetEntity, newList);
                    }
                }
            }
            else
            {
                if (sourceType.GetProperty(targetPropInfo.Name) != null)
                {
                    var obj = sourceType.GetProperty(targetPropInfo.Name);
                    if (obj.PropertyType.Namespace == "System.Collections.Generic")
                    {
                        //var x = targetType.GetProperty(targetPropInfo.Name);
                        //PopulateFromMessage(ref x, sourceType.GetProperty(targetPropInfo.Name));
                        continue;
                    }
                    targetPropInfo.SetValue(targetEntity, sourceType.GetProperty(targetPropInfo.Name).GetValue(message), null);
                }
            }
        }
    }

0
你应该为每个类创建一个接口(在接口中实现方法和属性),并在每个类中实现它。然后,在函数PopulateFromMessage中应指定允许使用的接口方法,这样你就可以直接使用T和TS泛型类型的类属性了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接