2017-03-01 5 views
1

Ich mache eine Hilfsmethode, wo es automatisch zufällige Werte zu einer Eigenschaft einer gegebenen Entität (Klasse) festlegen würde, so dass ich nicht jede Eigenschaft mit füllen muss ein Wert beim Testen.List <PropertyInfo> außer List <PropertyInfo> funktioniert nicht

In meinem Fall erbt jede Entität von BaseEntity-Klasse, die die Eigenschaften ID, CreatedBy, CreatedOn, etc ... hat. Im Grunde hat diese Klasse alle Eigenschaften, die über alle Entitäten verteilt sind.

Was ich hier erreichen möchte, ist, die einzigartigen Eigenschaften von den allgemeinen zu trennen.

Hier ist mein Code:

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

Die propeblem mit ist var propertiesToPopulate = entityBaseProperties.Except(ourEntityProperties).ToList();

Was erwarte ich eine Liste von Propertyinfo-Objekte, die nur einzigartig für diese Einheit sind, aber ich bin immer ALL bekommen die Eigenschaften meiner Entität. Diese Zeile filtert die Liste nicht wie beabsichtigt.

Irgendwelche Hilfe warum ??

+1

Wenn die Eigenschaften eindeutig sein sollten dem _derived_ Entitätstyp verwenden können, sollten nicht Es ist 'propertiesToPopulate = ourEntityProperties.Except (entityBaseProperties)'? –

+0

@ RenéVogt Ich dachte auch, dass es so funktionieren sollte. Aber das tut es nicht. –

Antwort

1

könnte andere Möglichkeit in der for-Schleife zu überprüfen, ob die DeclaringType das gleiche wie die Art von entity ist:

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

Dann würden Sie brauchen nur eine Schleife, die notwendigen Eigenschaften alle auszufiltern.

In einem „linqish“ oneliner Sie es als schreiben konnte:

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

Aber es sieht schrecklich aus;)

+0

Gut gearbeitet. Danke Herr: D –

+0

Aber wie kann ich auch die Navigationseigenschaften entfernen? –

+0

@ Ra'edAlaraj Was sind Navigationseigenschaften? –

3

PropertyInfo "weiß", welchen Typ Sie verwendet haben, um danach zu fragen. Zum Beispiel:

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

hat Ausgang:

False 
Base 
Child 

Glücklicherweise können Sie dies tun, viel mehr einfach - wenn Sie nur wollen wissen, welche Eigenschaften in TEntity deklariert wurden, können Sie nur verwenden:

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

Stellen Sie ein, wenn Sie auch statische Eigenschaften wünschen. Der wichtige Punkt ist BindingFlags.DeclaredOnly.

0

Property viele Attribute enthält, von denen einige Werte eindeutig den Objekttyp haben sie beziehen sich auf, so dass ich glaube, dass Sie nur für den Namen des bei der Prüfung interessiert sein Eigenschaft Attribut:

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

ich eine Klasse erstellt haben, die Sie für diese genaue Sache

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 

    } 

Sie müssen auch einige statische Erweiterungen

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 Danke, ich habe eine Ihrer Antworten verwendet, um diese Klasse zu erstellen –

Verwandte Themen