如何使用反射</string>在c#中的List <string>中获取每个字符串的值

时间:2014-07-24 16:49:37

标签: c# reflection

我想用模型对象值更新数据库对象 我如何获得作为List的modelObject内的属性值?

想象一下像这样的对象

public class Worker{
     public string Id { get; set; }
     public bool GoodPerson { get; set; }
     public bool Wise { get; set; }
     public List<string> Formation { get; set; }
}

我不知道如何从Formation属性中获取值,因此如何将Formation属性中的已编辑值反映到我的dataBaseObject中,您能帮助我吗?

我如何使用反射来反映这些变化?

public static void UpdateObjectFrom(this object modelObject, object dataBaseObject, string[] excludedProperties = null)
        {

            //WHAT IF THE modelObject is now List<string> ?????, how do i pass the values of modelObject for the dataBaseObject List<string> object


            Type modelObjectType = modelObject.GetType();
            Type dataBaseObjectType = dataBaseObject.GetType();

            PropertyInfo[] modelProperties = modelObjectType.GetProperties();
            PropertyInfo[] dataBaseProperties = dataBaseObjectType.GetProperties();

            if (excludedProperties != null)
            {
                dataBaseProperties = dataBaseProperties.Where(x => !excludedProperties.Contains(x.Name)).ToArray();
            }

            foreach (PropertyInfo dataBasePropInfo in dataBaseProperties)
            {
                if (HasSimpleType(dataBasePropInfo.PropertyType) || dataBasePropInfo.PropertyType.IsGenericType && dataBasePropInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    PropertyInfo modelPropInfo = modelObjectType.GetProperty(dataBasePropInfo.Name);

                    dataBasePropInfo.SetValue(dataBaseObject, modelPropInfo.GetValue(modelObject));
                }
                else if (dataBasePropInfo.PropertyType.IsGenericType)
                {
                    UpdateObjectFrom(dataBasePropInfo.GetValue(dataBaseObject, null), modelObjectType.GetProperty(dataBasePropInfo.Name).GetValue(modelObject, null));
                }
                else if (dataBasePropInfo.PropertyType.IsClass && !dataBasePropInfo.PropertyType.FullName.StartsWith("System."))
                {
                    UpdateObjectFrom(dataBasePropInfo.GetValue(dataBaseObject, null), modelObjectType.GetProperty(dataBasePropInfo.Name).GetValue(modelObject, null));
                }
            }
        }

        private static bool HasSimpleType(Type tipo)
        {
            return tipo.IsPrimitive || tipo == typeof(string) || tipo.IsEnum || tipo == typeof(Decimal) || tipo == typeof(DateTime);
        }

1 个答案:

答案 0 :(得分:0)

在您进一步阅读之前,我建议您查看AutoMapper。 AutoMapper旨在将数据从一种类型映射到另一种类型。从我看来,这就是你想要完成的事情。

需要注意的一点是,AutoMapper不会对列表执行深层复制。因此,如果修改源对象上的列表,它将影响目标对象上的列表。

浅拷贝是直接的,只是直接复制列表,就像你的原始和可空类型一样。

您的代码需要考虑的其他因素。您正在检查属性名称,但不检查两个对象的类型。如果您在另一个课程int Id上有string Id该怎么办?

如果您必须拥有该列表的深层副本,则会变得更复杂一些。但这是我想出的(注意:这不是一个真正的深层副本,因为列表的成员没有被克隆):

else if (dataBasePropInfo.PropertyType.IsGenericType)
{
    var args = dataBasePropInfo.PropertyType.GetGenericArguments();
    var lstType = typeof (List<>).MakeGenericType(args);
    if (lstType.IsAssignableFrom(dataBasePropInfo.PropertyType))
    {
        PropertyInfo modelPropInfo = modelObjectType.GetProperty(dataBasePropInfo.Name);
        var target = Activator.CreateInstance(lstType);
        var source = modelPropInfo.GetValue(modelObject);
        lstType.InvokeMember("AddRange", BindingFlags.InvokeMethod, null, target, new[] {source});

        dataBasePropInfo.SetValue(dataBaseObject, target);
    }
    else
    {
        UpdateObjectFrom(dataBasePropInfo.GetValue(dataBaseObject, null), modelObjectType.GetProperty(dataBasePropInfo.Name).GetValue(modelObject, null));
    }
}

推荐阅读:How to: Examine and Instantiate Generic Types with Reflection

另一个选项

您可以使用反射和序列化的组合。

  1. 将源对象序列化为流
  2. 反序列化源对象的新副本(新对象不会共享原始源的任何引用)
  3. 使用:dataBasePropInfo.SetValue(dataBaseObject, modelPropInfo.GetValue(modelObject));
  4. 将属性从source-clone复制到目标