C# 获取C#中某个对象的某种类型的所有属性

Die*_*ves 7 c#

我有一个有 10 个 IFormFiles 的对象。我想将它们放入 IFormFile 列表中,以便可以轻松操作。

public class Car{

 public IFormFile Imagem1 {get; set;}
 public IFormFile Imagem2 {get; set;}
......

}



 List<IFormFile> imagens = new List<IFormFile>();

foreach(IFormFile imagem in carro.)
  {
          imagens.add(...);
  }
Run Code Online (Sandbox Code Playgroud)

有没有办法将 IFormFile 传递给列表,或者我必须在 Car 对象中操作它们。

我忘了说我正在使用添加它们

images.add(car.Image1);

但我的代码变得混乱。因为我必须检查空值和许多其他事情。如果我可以循环获取 IFormFile,我的生活会轻松得多。

And*_*yCh 9

IFormFile下面的代码演示了如何从对象中获取类型的所有属性car

正如评论中提到的,反射 API 相当慢 - 考虑缓存PropertyInfo对象,或者更好的方法 - 使用表达式编译委托,这将迭代对象属性并将其值放入目标集合中。

void Main()
{
    var car = new Car();

    var imagens = typeof(Car).GetProperties()
        .Where(x => x.PropertyType == typeof(IFormFile))
        .Select(x => (IFormFile)x.GetValue(car))
        .Where(x => x != null)
        .ToList();
}
Run Code Online (Sandbox Code Playgroud)

属性信息缓存

PropertyInfo下面是如何将上述代码转换为使用缓存对象的示例:

void Main()
{
    var car = new Car();
    var imagens = PropertyGetter<Car, IFormFile>.GetValues(car);
}

public static class PropertyGetter<TObject, TPropertyType>
{
    private static readonly PropertyInfo[] _properties;

    static PropertyGetter()
    {
        _properties = typeof(TObject).GetProperties()
            // "IsAssignableFrom" is used to support derived types too
            .Where(x => typeof(TPropertyType).IsAssignableFrom(x.PropertyType))
            // Check that the property is accessible
            .Where(x => x.GetMethod != null && x.GetMethod.IsPublic && !x.GetMethod.IsStatic)
            .ToArray();
    }

    public static TPropertyType[] GetValues(TObject obj)
    {
        var values = _properties
            .Select(x => (TPropertyType) x.GetValue(obj))
            .ToArray();

        return values;
    }
}
Run Code Online (Sandbox Code Playgroud)

基于表达的

另一个示例展示了如何实现基于表达式选择特定类型的属性值的逻辑。

public static class PropertyGetterEx<TObject, TPropertyType>
{
    private static readonly Func<TObject, TPropertyType[]> _getterFunc;

    static PropertyGetterEx()
    {
        // The code below constructs the following delegate:
        //
        // o => object.ReferenceEquals(o, null)
        //      ? null
        //      : new TPropertyType[] { o.Prop1, o.Prop2, ... };
        //

        // An expression for the parameter `o`
        var objParam = Expression.Parameter(typeof(TObject), "o");

        // Create expressions for `o.Prop1` ... `o.PropN`
        var propertyAccessExprs = GetPropertyInfos()
            .Select(x => Expression.MakeMemberAccess(objParam, x));

        // Create an expression for `new TPropertyType[] { o.Prop1, o.Prop2, ... }`
        var arrayInitExpr = Expression.NewArrayInit(
            typeof(TPropertyType),
            propertyAccessExprs);

        // Create an expression for `object.ReferenceEquals(o, null)`
        var refEqualsInfo = typeof(object).GetMethod(nameof(object.ReferenceEquals));
        var refEqualsExpr = Expression.Call(
            refEqualsInfo,
            objParam,
            Expression.Constant(null, typeof(TPropertyType)));

        // The condition expression
        var conditionExpr = Expression.Condition(
            refEqualsExpr,
            Expression.Constant(null, typeof(TPropertyType[])),
            arrayInitExpr);

        _getterFunc = Expression
            .Lambda<Func<TObject, TPropertyType[]>>(
                conditionExpr,
                objParam)
            .Compile();
    }

    private static PropertyInfo[] GetPropertyInfos()
    {
        var properties = typeof(TObject).GetProperties()
            // "IsAssignableFrom" is used to support derived types too
            .Where(x => typeof(TPropertyType).IsAssignableFrom(x.PropertyType))
            // Check that the property is accessible
            .Where(x => x.GetMethod != null && x.GetMethod.IsPublic && !x.GetMethod.IsStatic)
            .ToArray();

        return properties;
    }

    public static TPropertyType[] GetValues(TObject obj)
    {
        return _getterFunc(obj);
    }
}
Run Code Online (Sandbox Code Playgroud)

基准测试结果

下面是上面提供的 3 种方法的基准测试结果(无缓存、有 PropertyInfo 缓存、基于表达式)。正如预期的那样,基于表达式的解决方案的性能比其他解决方案好得多:

|               Method |      Mean |    Error |   StdDev | Rank |
|--------------------- |----------:|---------:|---------:|-----:|
|              NoCache | 789.99 ns | 4.669 ns | 4.139 ns |    3 |
|    PropertyInfoCache | 417.32 ns | 3.271 ns | 3.059 ns |    2 |
| ExpressionBasedCache |  27.55 ns | 0.091 ns | 0.085 ns |    1 |
Run Code Online (Sandbox Code Playgroud)


Gre*_*rko 7

这是一个从提供的对象返回指定类型的所有属性的方法:

public static List<TProperty> GetAllPropertyValuesOfType<TProperty>(this object obj)
{
    return obj.GetType()
        .GetProperties()
        .Where(prop => prop.PropertyType == typeof(TProperty))
        .Select(pi => (TProperty)pi.GetValue(obj))
        .ToList();
}
Run Code Online (Sandbox Code Playgroud)

你可以这样使用它:

Car myCar;
List<IFormFile> imagesOfMyCar = myCar.GetAllPropertyValuesOfType<IFormFile>();
Run Code Online (Sandbox Code Playgroud)