使用反射我们如何判断 class 属性 是否为可空集合并获取其数据类型?

Using reflection how can we tell if a class property is a nullable collection and get its data type?

I have no problems with properties that are non-nullable collections but everything changes when the property is a nullable collection...

给定一个 class 具有可为空的集合属性(int?[], long?[], List, ...)

public class SomeClass
{
    public int?[] PropertyX { get; set; }
    public long?[] PropertyY { get; set; }
    public float?[] PropertyZ { get; set; }
    public List<decimal?> PropertyList { get; set; }
    public string Name { get; set; }
} 

如何判断 属性 是否为可为 null 的集合
可为 null 的集合是否有 任何实际值
最后,可空集合数据类型是什么?

public class SomeOtherClass
{
    public string Discover(SomeClass someClass)
    {
        var sb = new StringBuilder();
        foreach (var propertyInfo in someClass.GetType().GetProperties())
        {
            var propValue = propertyInfo.GetValue(someClass, new object[] { });
            if (propValue.IsNullableCollection() && propValue.HasValue())
            {
                sb.AppendFormat("{0} data type is {1}", propValue.GetDataType());
            }
        }
        return sb.ToString();
    }
}

示例:

void Main
{
  var sc = new SomeClass() 
  {
    PropertyX = new int?[2]{50,10}
  };
  var output = new SomeOtherClass().Discover(sc); 
  
  //Display Output ...
}

"PropertyX has values and data type is int."

我写了一个方法,应该可以为您提供完成任务所需的所有工具:

public static void Discover(Type mainType)
{
    foreach (var pi in mainType.GetProperties())
    {
        var t = pi.PropertyType;
        if (t.IsArray)
        {
            (var isNullable, var innerT) = ExamineForNullable(t.GetElementType());
            Console.WriteLine($"{pi.Name} data type is an array of {innerT} (nullable: {isNullable})");
        }
        else if (t.GetInterface(nameof(ICollection)) != null)
        {
            //TODO this is true for dictionaries too!
            if (t.IsGenericType)
            {
                (var isNullable, var innerT) = ExamineForNullable(t.GetGenericArguments()[0]);
                Console.WriteLine($"{pi.Name} data type is collection of {innerT} (nullable: {isNullable})");
            }
            else
            {
                //TODO
            }

        }
        else
        {
            Console.WriteLine($"{pi.Name} data type is {t}");
        }
    }
}

static (bool nullable, Type type) ExamineForNullable(Type t)
    => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)
            ? (true, Nullable.GetUnderlyingType(t))
            : (false, t);

让我们 运行 使用以下 class,这是您示例 class 的修改版本:

public class SomeClass
{
    public int?[] PropertyX { get; set; }

    public List<decimal?> List1 { get; set; }

    public List<decimal> List2 { get; set; }

    public string Name { get; set; }

    public Dictionary<string, decimal?> Dictionary { get; set; }
}

(...) 

Discover(typeof(SomeClass));

请注意,您不需要 class 的对象来检查类型:Discover( new SomeClass())Discover(typeof(SomeClass)

输出为:

PropertyX data type is an array of System.Int32 (nullable: True)
List1 data type is collection of System.Decimal (nullable: True)
List2 data type is collection of System.Decimal (nullable: False)
Name data type is System.String
Dictionary data type is collection of System.String (nullable: False)