为什么 GetProperties() 在使用 typeof() 时不返回属性,但在使用 GetType() 时却返回?

Jay*_*Jay 2 c#

我有一个 C# 代码,它会查看类上的每个公共属性并创建键和值的集合。关键只是一个访问属性的点符号变量;

我有以下型号

public class Home
{
    public string Id { get; set; }
    public string Summary { get; set; }
    public Address Address { get; set; }
}

public class Address 
{
    public Street Street { get; set; }
    public string CityName { get; set; }
    public string StateName { get; set; }
}

public class Street
{
    public string Number { get; set; }
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后我有以下功能

public void GetPropertyKeyValue<T>(T obj, string prefix, List<ExtractedTerm> pairs)
{
    if (pairs == null)
    {
        throw new ArgumentNullException(nameof(pairs));
    }

    // This works of the first object, but fails on the class properties
    var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

    foreach (var property in properties)
    {
        string key = property.Name;

        if (!string.IsNullOrWhiteSpace(prefix))
        {
            key = $"{prefix}.{property.Name}";
        }

        Type type = property.PropertyType;
        object value = property.GetValue(obj, null);

        if (type.IsClass && !type.IsInterface && !type.IsEnum && !type.IsPrimitive && !type.IsString())
        {
            GetPropertyKeyValue(value, key, ref pairs);

            continue;
        }

        pairs.Add(new ExtractedTerm(key, value, property.PropertyType));
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的方法是这样调用的

var home = new Home() {
   Id = "100",
   Summary = "Test",
   Address = new Address() {
       CityName = "Los Angeles"
   }
}

var pairs = new List<ExtractedTerm>();
GetPropertyKeyValue(home, null, pairs);
Run Code Online (Sandbox Code Playgroud)

上面的代码在Home.Idand 和Home.Summaryand上完美地工作,Home.Address但是正弦Address是类类型的is 属性,因此该GetPropertyKeyValue方法被递归调用。当Address被传递的代码typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)不返回任何属性。但是,代码obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)返回预期的属性。但我真的不能算obj.GetType()为 obj 可能为空。正如您在上面的示例中注意到的,该Street属性为 null 并且obj.GetType()会引发异常。

为什么typeof()在某些情况下有效,但并非总是如此?即使obj为空,如何始终获得属性?

Hei*_*nzi 6

类型推断发生在编译时。

换句话说,由于value是静态类型object

object value = property.GetValue(obj, null);
Run Code Online (Sandbox Code Playgroud)

以下行:

GetPropertyKeyValue(value, key, ref pairs);
Run Code Online (Sandbox Code Playgroud)

被编译为

GetPropertyKeyValue<object>(value, key, ref pairs);
Run Code Online (Sandbox Code Playgroud)

typeof(object)产生......好吧......object类型。


如何解决这个问题?传入一个类型为 的参数,而不是使方法通用Type。这样,您只需传入property.PropertyType递归调用即可。我建议使用以下签名:

public void GetPropertyKeyValue<T>(T obj, string prefix, List<ExtractedTerm> pairs)
{
    return GetPropertyKeyValue(typeof(T), obj, prefix, pairs);
}

private void GetPropertyKeyValue(Type type, object obj, string prefix, List<ExtractedTerm> pairs)
{
    // contains your logic and recursively calls the non-generic version
    ...
}
Run Code Online (Sandbox Code Playgroud)