使用c#中的反射添加到未知类型的集合

时间:2014-12-12 14:44:57

标签: c# reflection collections properties

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

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; }
}

然后我使用Reflection从源填充目标。

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中的值填充它们。最后,它几乎是TargetObject形式的SourceMessage的副本。

这一切都源于接收消息并将它们转换为具有相同属性名称的对象。

3 个答案:

答案 0 :(得分:0)

您应该为每个类创建一个接口(在接口上实现方法和属性)并在每个类中实现它。之后,在函数PopulateFromMessage中应该指定方法中允许的接口,使用它可以直接使用带有T和TS泛型类的类的属性。

答案 1 :(得分: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);
                }
            }
        }
    }

答案 2 :(得分:0)

如果你的问题是在一个集合中迭代单个属性中包含的项目,那么关键是将属性值读入动态变量而不是默认情况下的对象变量,这样你就可以使用了一个foreach为它。

dynamic propVal = inputProperty.GetValue(item);
foreach (var subItem in propVal)
{    
//do your stuff
}