使用反射基于类型查找和更新对象

时间:2018-02-19 16:25:36

标签: c# reflection

我正在尝试检查嵌套对象中的值,并在必要时替换它们。使用反射我可以迭代所有嵌套对象并获取属性类型,但我卡住检索值并替换值。我把一个简单的例子汇总在一起。

说我有以下型号:

public class Employee
{
    #region Members
    private string _FirstName;
    private string _LastName;
    private StreetAddress _EmployeeAddress;
    #endregion
    #region Properties
    public string FirstName { get { return _FirstName; } set { value = _FirstName; } }
    public string LastName { get { return _LastName; } set { value = _LastName; } }
    public StreetAddress EmployeeAddress { get { return _EmployeeAddress; } set { value = _EmployeeAddress; } }
    #endregion
}

public class StreetAddress
{
    #region Members
    private string _Street;
    private string _City;
    private string _State;
    private string _Zip;
    #endregion
    #region Properties
    public string Street { get { return _Street; } set { value = _Street; } }
    public string City { get { return _City; } set { value = _City; } }
    public string State { get { return _State; } set { value = _State; } }
    public string Zip { get { return _Zip; } set { value = _Zip; } }
    #endregion
}

在我的方案中,我需要将 StreetAddress 中的街道“123 Main Street”更新为“999 Main Street” 用于 StreetAddress 所在的任何对象。 StreetAddress 对象可以出现在任何给定对象的任何级别。 因此,假设我将员工强制转换为对象,并且我使用以下内容迭代员工对象,以查找 StreetAddress 类型。

private static void ReadPropertiesRecursive2(Type type)
{
    foreach (PropertyInfo property in type.GetProperties())
    {

        if (property.PropertyType == typeof(StreetAddress))
        {
            Debug.WriteLine(property.Name);

            Type StreetAddressType = property.GetType();

            //Get the value of 'Street'  
            //Here is where I'm having trouble figuring out how to get the value

            Debug.WriteLine(StreetAddressType.GetProperty("Street").GetValue(StreetAddressType, null));
            //The above throws the Exception: 'System.Reflection.TargetException'

            //Check the value of 'Street'

            //Replace the value of 'Street'

        }
        if (property.PropertyType.IsClass)
        {
            ReadPropertiesRecursive2(property.PropertyType);
        }
    }
}

用法:

ReadPropertiesRecursive2(Employee.GetType());

我不确定我在语法中缺少什么来使用1)返回值和2)必要时更新值。如果你能指出我正确的方向,那将是非常棒的,或者如果有更好的方法,我有兴趣了解它。提前谢谢!

3 个答案:

答案 0 :(得分:1)

您最大的问题是GetValue需要实际对象来获取值。 PropertyInfo就此而言,Type只是元数据。换句话说,GetValue的有效用法如下:

Employee emp = new Employee();
PropertyInfo addressProp = typeof(Employee).GetProperty("StreetAddress");
string address = addressProp.GetValue(emp);

(传递null尝试将其从“static”实例中删除“以获取其价值”

重构代码以获取和设置实际实例,你应该没问题。

答案 1 :(得分:0)

你的问题在于你正在喂食一种物体,而不是物体本身。

当您将参数提供为

ReadPropertiesRecursive2(Employee.GetType());

您没有提供Employee对象本身,而是提供对象的“类型”。 因此,当您要求它读取这些属性的值时,它会说“在哪个对象上读取此属性或字段?”

StreetAddressType.GetProperty("Street").GetValue(StreetAddressType, null);

上面的null,需要是您正在处理的实际对象。 将您的方法签名更改为:

private static void ReadPropertiesRecursive2(Type type, object obj)

然后将保存数据的实际对象作为第二个参数提供。

然后您可以执行:

StreetAddressType.GetProperty("Street").GetValue(StreetAddressType, obj);

现在,您将告诉它阅读obj对象上的“街道”字段。

答案 2 :(得分:0)

  

如果你能指出我正确的方向,那将是非常棒的,或者如果有更好的方法我会有兴趣了解它。

这个答案更倾向于“指向正确的方向”类别。

您似乎想要更新各种实体上的街道地址,这些实体可能在其结构中的某处包含StreetAddress的实例,可能嵌套了几个级别。

这个问题的根本问题是我们的代码应该编写为与特定类的特定属性进行交互。我们需要知道我们想要更新哪个属性并更新该属性,而不仅仅是更新任何看起来可能是正确属性的属性,因为它属于某种类型。

考虑这个例子:

public class Employee
{
    public StreetAddress Address {get;set;}
    public EmergencyContact EmergencyContact {get;set;}
}

public class EmergencyContact
{
    public StreetAddress Address {get;set;}
}

如果您以“正常”方式更新地址:

employee.StreetAddress = updatedAddress;

employee.EmergencyContact.StreetAddress = updatedAddress;

然后你没事。

但如果你做这样的事情:

UpdateStreetAddress(object something, "123 Maple St.")

...然后它会查找每个StreetAddress,它会在该对象的任何位置更新每个 StreetAddress。它将设置员工的地址和员工的紧急联系地址。

尝试编写一个适合每个班级的“一刀切”方法是不值得的。只编写能够更新您需要更新的代码的代码要好得多。如果它是一些更多的代码(虽然它可能不会是。),这是没关系的。你可以通过不处理缺陷,意外的副作用以及未来的开发人员不必弄清楚发生了什么来获得时间。