简体   繁体   English

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

[英]C# get all properties of a certain type of an object in C#

I have an object that has 10 IFormFiles.我有一个包含 10 个 IFormFiles 的对象。 I want to put them into a list of IFormFile so that it can be manipulated easily.我想将它们放入 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(...);
  }

Is there a way to pass the IFormFile to a lista, or will I have to manipulate use them in the Car object.有没有办法将 IFormFile 传递给列表,或者我是否必须在 Car 对象中操作使用它们。

I forgot to say I was adding them using我忘了说我正在添加它们

images.add(car.Image1);图像。添加(汽车。图像1);

But my code is getting messy.但是我的代码越来越乱了。 Because I have to check for nulls and many other things.因为我必须检查空值和许多其他事情。 If I could get the IFormFile in a loop my life will be much easier.如果我可以在循环中获取 IFormFile,我的生活就会容易得多。

The code below demonstrates how to get all the properties of type IFormFile from the object car .下面的代码演示了如何从对象car获取IFormFile类型的所有属性。

As it was mentioned in the comments, Reflection API is quite slow - consider caching PropertyInfo objects, or what is better - using Expressions to compile a delegate, that would iterate over the object properties and put their values into a target collection.正如评论中提到的,反射 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();
}

PropertyInfo caching属性信息缓存

Below is a sample of how the code above can be transformed to use cached PropertyInfo objects:下面是如何将上面的代码转换为使用缓存的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;
    }
}

Expression-based基于表达式

Another sample showing how it's possible to implement the logic of selecting property values of specific type based on Expressions.另一个示例展示了如何实现基于表达式选择特定类型的属性值的逻辑。

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);
    }
}

Benchmark results基准测试结果

Below are benchmark results for the 3 approaches provided above (no cache, with PropertyInfo cache, Expression-based).下面是上面提供的 3 种方法的基准测试结果(无缓存、使用 PropertyInfo 缓存、基于表达式)。 As expected, the Expression-based solution performs much better than the others:正如预期的那样,基于表达式的解决方案的性能比其他解决方案要好得多:

|               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 |

Here is a method that returns all properties of the specified type from the provided object:这是一个从提供的对象返回指定类型的所有属性的方法:

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();
}

You can use it like this:你可以这样使用它:

Car myCar;
List<IFormFile> imagesOfMyCar = myCar.GetAllPropertyValuesOfType<IFormFile>();

You may be use reflection.您可能正在使用反射。 GetProperties method return all of properties specific type. GetProperties 方法返回所有特定类型的属性。

For example your code must be as below :例如,您的代码必须如下:

using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{
    public class Car
    {

        public IFormFile Imagem1 { get; set; }
        public IFormFile Imagem2 { get; set; }
        public IFormFile Imagem3 { get; set; }
        //and etc
    }

    public class Example
    {
        public static void Main()
        {
            List<IFormFile> imagens = new List<IFormFile>();

            var car = new Car();

            var carType = car.GetType();
            var ifromFileProperties = carType.GetProperties().Where(x => x.PropertyType == typeof(IFormFile)).ToArray();

            foreach (var property in ifromFileProperties)
            {
                var image = (IFormFile)property.GetValue(car, null);
                imagens.Add(image);
            }
        }
    }
}

At last there are all the items which type of property is IFormFile in the list最后在列表中列出了所有属性类型为 IFormFile 的项目

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM