Reputation: 2687
I have an object that has 10 IFormFiles. I want to put them into a list of IFormFile so that it can be manipulated easily.
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.
I forgot to say I was adding them using
images.add(car.Image1);
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.
Upvotes: 10
Views: 10452
Reputation: 5470
You may be use reflection. GetProperties method return all of properties specific type.
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
Upvotes: 0
Reputation: 1413
The code below demonstrates how to get all the properties of type IFormFile
from the object car
.
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.
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();
}
Below is a sample of how the code above can be transformed to use cached PropertyInfo
objects:
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;
}
}
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);
}
}
Below are benchmark results for the 3 approaches provided above (no cache, with PropertyInfo cache, Expression-based). 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 |
Upvotes: 12
Reputation: 2877
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>();
Upvotes: 7