2017-03-01 113 views
1

我做了一个帮助器方法,它会自动将随机值设置为给定实体(类)的属性,这样我就不必为每个属性填充测试时的值。列表<PropertyInfo>除列表<PropertyInfo>不工作

就我而言,每个实体都继承自BaseEntity类,它具有ID,CreatedBy,CreatedOn等等属性。基本上这个类具有所有实体共享的所有属性。

我在这里想要完成的是将独特的属性与常见的属性分开。

这里是我的代码:

public static TEntity PopulateProperties<TEntity>(TEntity entity) 
{ 
    try 
    { 
     // Since every entity inherits from EntityBase, there is no need to populate properties that are in EntityBase class 
     // because the Core project populates them. 
     // First of all, we need to get all the properties of EntityBase 
     // and then exlude them from the list of properties we will automatically populate 

     // Get all properties of EntityBase 
     EntityBase entityBase = new EntityBase(); 
     List<PropertyInfo> entityBaseProperties = new List<PropertyInfo>(); 
     foreach (var property in entityBase.GetType().GetProperties()) 
     { 
      entityBaseProperties.Add(property); 
     } 

     // Get all properties of our entity 
     List<PropertyInfo> ourEntityProperties = new List<PropertyInfo>(); 
     foreach (var property in entity.GetType().GetProperties()) 
     { 
      ourEntityProperties.Add(property); 
     } 

     // Get only the properties related to our entity 
     var propertiesToPopulate = ourEntityProperties.Except(entityBaseProperties).ToList(); 

     // Now we can loop throught the properties and set values to each property 
     foreach (var property in propertiesToPopulate) 
     { 
      // Switch statement can't be used in this case, so we will use the if clause     
      if (property.PropertyType == typeof(string)) 
      { 
       property.SetValue(entity, "GeneratedString"); 
      } 
      else if (property.PropertyType == typeof(int)) 
      { 
       property.SetValue(entity, 1994); 
      } 
     } 

     return entity; 
    } 
    finally 
    { 
    } 
} 

的propeblem是var propertiesToPopulate = entityBaseProperties.Except(ourEntityProperties).ToList();

什么我期待的是,只有唯一这个实体的PropertyInfo对象的列表,但是我从来都是让我的实体的属性。 此行不会按预期过滤列表。

任何帮助为什么?

+1

如果属性应该是唯一的_derived_实体类型,不应该它是'propertiesToPopulate = ourEntityProperties.Except(entityBaseProperties)'? –

+0

@RenéVogt我也认为这种方式应该在理论上起作用。但事实并非如此。 –

回答

1

另一种可能是在你的检查回路​​是否相同的entity类型:

// Get all properties of our entity 
List<PropertyInfo> ourEntityProperties = new List<PropertyInfo>(); 
foreach (var property in entity.GetType().GetProperties()) 
{ 
    // check whether it only belongs to the child 
    if (property.DeclaringType.Equals(entity.GetType())) 
    { 
     ourEntityProperties.Add(property); 
    }  
} 

那么你就只需要一个循环过滤掉所有必要的属性。

在“linqish” oneliner你可以写为:

List<PropertyInfo> ourEntityProperties = entity.GetType().GetProperties().Where(x=>x.DeclaringType.Equals(entity.GetType())).ToList(); 

但它看起来可怕;)

+0

工作得很好。谢谢先生:D –

+0

但是我怎样才能删除导航属性? –

+0

@ Ra'edAlaraj什么是导航属性? –

3

PropertyInfo“知道”您用来请求它的类型。例如:

using System; 
using System.Reflection; 

class Base 
{ 
    public int Foo { get; set; } 
} 

class Child : Base 
{  
} 

class Test 
{ 
    static void Main() 
    { 
     var baseProp = typeof(Base).GetProperty("Foo"); 
     var childProp = typeof(Child).GetProperty("Foo"); 
     Console.WriteLine(baseProp.Equals(childProp)); 
     Console.WriteLine(baseProp.ReflectedType); 
     Console.WriteLine(childProp.ReflectedType); 
    } 
} 

具有的输出:

False 
Base 
Child 

幸运的是,你可以有很多更简单地做到这一点 - 如果你只是想知道TEntity中声明你可以使用它的属性:

var props = typeof(entity.GetType()).GetProperties(BindingFlags.Instance | 
                BindingFlags.Public | 
                BindingFlags.DeclaredOnly); 

如果您还想要静态属性,请进行调整。重要的一点是BindingFlags.DeclaredOnly

0

的PropertyInfo包含许多属性,其中有一些独特的对象类型的值他们提到,所以我相信你可能感兴趣的只是检查了属性的名称属性:

//properties whose names are unique to our Entity 
var propertiesToPopulate = ourEntityProperties 
    .Where(oep => !entityBaseProperties.Any(ebp => ebp.Name == oep.Name)).ToList(); 
0

我创建了一个类,你可以使用这个确切的事情

public class DTOGeneratorRule 
    { 
     #region Members 

     protected Random _random; 

     protected readonly Dictionary<Type, Func<object>> typeToRandomizerFuncMap = new Dictionary<Type, Func<object>> 
     { 
     }; 

     #endregion 

     #region Constructors 

     public DTOGeneratorRule() 
     { 
      // Do Not Change this 
      // This is explicitly set to assure that values are generated the same for each test 
      _random = new Random(123); 

      typeToRandomizerFuncMap.Add(typeof(int),() => _random.Next()); 
      typeToRandomizerFuncMap.Add(typeof(bool),() => _random.Next() % 2 == 0); 
      // Most codes on our system have a limit of 10, this should be fixed when configuration exits 
      typeToRandomizerFuncMap.Add(typeof(Guid),() => Guid.NewGuid()); 
      typeToRandomizerFuncMap.Add(typeof(string),() => _random.GetRandomAlphanumericCode(10)); 
      //Most of the times we need to work with dates anyway so truncate the time 
      typeToRandomizerFuncMap.Add(typeof(DateTime),() => DateTime.Now.Date); 
      typeToRandomizerFuncMap.Add(typeof(Char),() =>_random.GetRandomAlphanumericCode(1)[0]); 
      typeToRandomizerFuncMap.Add(typeof(Double),() => _random.NextDouble()); 
      typeToRandomizerFuncMap.Add(typeof(float),() => _random.NextFloat()); 
      typeToRandomizerFuncMap.Add(typeof(Decimal),() => _random.NextDecimal()); 
     } 

     #endregion 

     #region Public Methods 

     public T SetAutoGeneratedDTOValues<T>(IEnumerable<Action<T>> explicitValueSetters = null, Dictionary<string, Type> typeCaster = null) 
      where T : new() 
     { 
      T initialDTO = new T(); 
      return this.SetAutoGeneratedDTOValues<T>(initialDTO, explicitValueSetters, typeCaster); 
     } 

     public T SetAutoGeneratedDTOValues<T>(T initialDTO, IEnumerable<Action<T>> explicitValueSetters = null, Dictionary<string, Type> typeCaster = null) 
     { 
      if (null == initialDTO) 
      { 
       throw new ArgumentNullException(nameof(initialDTO)); 
      } 

      //TODO: This needs to work with Members as well 
      foreach (var property in typeof (T).GetProperties()) 
      { 
       if (null == property.GetSetMethod()) 
       { 
        continue; 
       } 

       object value = null; 

       Type propertyType = property.PropertyType; 
       if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) 
       { 
        propertyType = Nullable.GetUnderlyingType(propertyType); 
       } 

       var targetType = propertyType; 
       if (typeCaster != null && typeCaster.ContainsKey(property.Name)) 
       { 
        targetType = typeCaster.Get(property.Name); 
       } 

       value = this.GetRandomValue(targetType); 
       value = this.convertToType(value, propertyType); 

       property.SetValue(initialDTO, value); 
      } 

      if (null != explicitValueSetters) 
      { 
       foreach (var setter in explicitValueSetters) 
       { 
        setter.Invoke(initialDTO); 
       } 
      } 

      return initialDTO; 
     } 

     #endregion 

     #region Protected Methods 

     protected object convertToType(object value, Type type) 
     { 
      return Convert.ChangeType(value, type); 
     } 

     protected bool TryGetRandomValue(Type type, out object value) 
     { 
      Func<object> getValueFunc; 
      if (type.IsEnum) 
      { 
       var values = Enum.GetValues(type); 
       int index = _random.Next(0, values.Length); 
       value = values.GetValue(index); 
       return true; 
      } 

      if (typeToRandomizerFuncMap.TryGetValue(type, out getValueFunc)) 
      { 
       value = getValueFunc(); 
       return true; 
      } 

      value = null; 
      return false; 
     } 

     protected object GetRandomValue(Type type) 
     { 
      object value = null; 
      Func<object> getValueFunc; 
      if (type.IsEnum) 
      { 
       var values = Enum.GetValues(type); 
       int index = _random.Next(0, values.Length); 
       value = values.GetValue(index); 
      } 
      else if (typeToRandomizerFuncMap.TryGetValue(type, out getValueFunc)) 
      { 
       value = getValueFunc(); 
      } 
      else 
      { 
       value = this.getDefault(type); 
      } 

      return value; 
     } 

     protected object getDefault(Type type) 
     { 
      if (type.IsValueType) 
      { 
       return Activator.CreateInstance(type); 
      } 
      return null; 
     } 

     #endregion 

    } 

你还需要一些静态扩展

public static class RandomExtensions 
{ 
    public static decimal NextDecimal(this Random rng) 
    { 
     // The max value should not be too large to avoid out of range errors when saving to database. 
     return Math.Round(rng.NextDecimal(10000, 25), 2); 
    } 

    //From Another Jon Skeet: http://stackoverflow.com/a/3365374/1938988 
    public static float NextFloat(this Random rng) 
    { 
     // Perform arithmetic in double type to avoid overflowing 
     double range = (double)float.MaxValue - (double)float.MinValue; 
     double sample = rng.NextDouble(); 
     double scaled = (sample * range) + float.MinValue; 
     return (float)scaled; 
    } 

    public static string GetRandomAlphanumericCode(this Random random, int length) 
    { 
     string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
     return RandomExtensions.GetRandomString(random, length, chars); 
    } 
} 
+0

@JonSkeet谢谢,我使用其中一个答案来帮助构建此类 –