使用反射访问已知类的某个未知字段

时间:2016-11-17 09:01:38

标签: c# reflection

说我有以下课程:

class Person
{
     public FirstType firstField ; // has a getter-setter  
     public SecondType secondField; // has a getter-setter  
     // more fields of other types
} 

我想构建一个函数,接受Person类作为其第一个参数,并将第一个参数字段之一的类型作为其第二个参数 - 假设{ {1}}的字段属于不同类型。

我的目标是能够对第二个参数使用反射,然后使用一些等效的点符号来访问传递的类。

Person

怎么做?

3 个答案:

答案 0 :(得分:0)

可以使用反射轻松完成:您可以获取类型的所有公共属性,查找给定类型的公共属性,并在传递的person实例的上下文中设置其值。

我还建议使用通用方法以获得更好的类型安全性和更简洁的用法:

public static void SetPersonField<T>(Person person, T value)
{
    typeof (Person)
        .GetProperties()
        .Single(p => p.PropertyType == typeof(T))
        .SetValue(person, value);
}

// Usage (both are correct):
SetPersonField(person, FirstType.EnumValue);
SetPersonField<FirstType>(person, FirstType.EnumValue);

您甚至不需要指定泛型类型,因为可以从输入参数中理解它。

请注意,如果此类型的属性,或者此类型的多个属性,.Single将引发异常。如果无法保证存在或唯一性,则需要使用SetPersonField方法处理它 此外,请始终牢记使用反射时的巨大性能下降。

如何更通用?

您可以实现更通用的方法,该方法将支持任何类型的属性和对象

public static void SetField<TObject, TProperty>(TObject obj, TProperty value)
{
    typeof(TObject)
        .GetProperties()
        .Single(p => p.PropertyType == typeof(TProperty))
        .SetValue(obj, value);
}

var person = new Person();
SetField(person, 123); // finds the only int property and sets its value
SetField(person, FirstType.EnumValue); // find the only FirstType property
SetField<Person, DateTime?>(person, DateTime.Now); // finds the only DateTime? property

请注意,对于某些特定类型(f.i.,Nullable),您需要明确指定类型,因为无法从您的数据中理解它。

答案 1 :(得分:0)

我前段时间使用过这门课程

Public Class PropertySetter

Public Shared Sub SetObjectProperty(ByRef obj As Object, propertyInfo As PropertyInfo, propertyValue As Object)
    'if we do not need to convert propertyValue to certain type
    If IsNothing(propertyValue) OrElse propertyInfo.PropertyType = propertyValue.GetType() Then
        obj.GetType().GetProperty(propertyInfo.Name).SetValue(obj, propertyValue)
    Else
        'Convert.ChangeType does not handle conversion to nullable types
        'if the property type is nullable, we need to get the underlying type of the property
        Dim targetType = If(IsNullableType(propertyInfo.PropertyType), Nullable.GetUnderlyingType(propertyInfo.PropertyType), propertyInfo.PropertyType)

        'convert Enum
        If (propertyValue.GetType() = GetType(String)) Then
            If propertyInfo.PropertyType.IsEnum OrElse (Not Nullable.GetUnderlyingType(propertyInfo.PropertyType) Is Nothing AndAlso Nullable.GetUnderlyingType(propertyInfo.PropertyType).IsEnum) Then
                'if propertyValue is equal to enum value
                Try
                    propertyValue = [Enum].Parse(targetType, propertyValue.ToString())
                Catch ex As Exception
                    'if propertyValue is equal to enum description 
                    Dim enumValues = targetType.GetFields()
                    For Each enumValue In enumValues
                        Dim descriptionAttribute = enumValue.GetCustomAttribute(Of DescriptionAttribute)()
                        If Not descriptionAttribute Is Nothing Then
                            If (descriptionAttribute.Description.Trim().ToUpper() = propertyValue.ToString().ToUpper()) Then
                                propertyValue = enumValue.GetValue(Nothing)
                                Exit For
                            End If
                        End If
                    Next
                End Try
            End If
        End If

        'set object property via reflection
        obj.GetType().GetProperty(propertyInfo.Name).SetValue(obj, Convert.ChangeType(propertyValue, targetType, CultureInfo.InvariantCulture))
    End If
End Sub

Private Shared Function IsNullableType(type As Type) As Boolean
    Return type.IsGenericType AndAlso type.GetGenericTypeDefinition().Equals(GetType(Nullable(Of )))
End Function
End Class

P.S。正如你所看到的vb.net。您可以使用this服务获取C#代码

答案 2 :(得分:0)

以下参考,以下是如何进行Getter查询:

public static object GetPersonField(Person person, Type fieldType)
{
    return typeof (Person)
            .GetProperties()
            .Single(p => p.PropertyType == fieldType)
            .GetValue(person);
}