2010-09-27 3 views
3

J'ai deux méthodes d'extension qui sont très similaires. Je voudrais supprimer le code duplique avec «the hole in the middle» modèle ou similaire, mais ne peut pas vraiment le faire fonctionner.Comment supprimer le code répétitif qui diffère en utilisant les propriétés/champs pour s'afficher eux-mêmes en tant que chaînes?

Le code ressemble à ceci:

public static String GetPublicPropertiesAsString(this Object @this) 
{ 
    return @this.GetType().GetProperties() 
     .Select(propertyInfo => 
         { 
          var propertyValue = propertyInfo.GetValue(obj: @this, 
                    invokeAttr: BindingFlags.Public, 
                    binder: null, 
                    index: null, 
                    culture: null); 

          var propertyValueAsString = propertyValue != null ? propertyValue.ToString().RemoveAll("00:00:00") : "[null]"; 

          return "{0}: {1}".FormatWith(propertyInfo.Name, propertyValueAsString); 
         }).JoinAsString(Environment.NewLine); 
} 

public static String GetFieldsAsString(this Object @this) 
{ 
    return @this.GetType().GetFields() 
     .Select(fieldInfo => 
         { 
          var fieldValue = fieldInfo.GetValue(@this); 

          var fieldValueAsString = fieldValue != null ? fieldValue.ToString().RemoveAll("00:00:00") : "[null]"; 

          return "{0}: {1}".FormatWith(fieldInfo.Name, fieldValueAsString); 
         }).JoinAsString(Environment.NewLine); 
} 

le code répétitif ci-dessus pourrait être remaniée loin? Remarque: JoinAsString, RemoveAll et FormatWith sont mes propres méthodes d'extension.

Répondre

3

Oui, il peut. En utilisant des génériques et le fait que PropertyInfo et FieldInfo dérivent de MemberInfo.

Quelque chose comme ceci:

static string GetAsString<T> 
    (object @this, Func<T, object> getter) where T : MemberInfo 
{ 
    return @this.GetType().GetMembers(/* binding flags */).OfType<T>().Select(
    x => 
    { 
     var value = getter(x); 
     var valueAsString = value != null ? value.ToString(). 
      RemoveAll("00:00:00") : "[null]"; 
     return "{0}: {1}".FormatWith(x.Name, valueAsString); 
    }).JoinAsString(); 
} 

Maintenant, le HOO:

public static String GetPublicPropertiesAsString(this Object @this) 
{ 
    return GetAsString<PropertyInfo>(@this, x => x.GetValue(@this, null)); 
} 

public static String GetPublicFieldsAsString(this Object @this) 
{ 
    return GetAsString<FieldInfo>(@this, x => x.GetValue(@this)); 
} 
+1

+1 et accepté. Merci! –

0

Je refactoriserait ce code intermédiaire en une seule méthode qui accepte MemberInfo[] et effectue un basculement sur le type de membre. Non testé, mais:

private static string GetMembersAsString(object @this, MemberInfo[] members) 
    { 
     var sb = new StringBuilder(); 
     for (int i = 0; i < members.Length; i++) 
     { 
      var member = members[i]; 
      if (i != 0) sb.AppendLine(); 
      object value; 
      switch(member.MemberType) { 
       case MemberTypes.Field: 
        value = ((FieldInfo)member).GetValue(@this); 
        break; 
       case MemberTypes.Property: 
        value = ((PropertyInfo)member).GetValue(@this, null); 
        break; 
       default: 
        throw new NotSupportedException(member.MemberType.ToString()); 
      } 
      string s = value == null ? "[null]" : value.ToString().RemoveAll("00:00:00"); 
      sb.Append(member.Name).Append(" = ").Append(s); 
     } 
     return sb.ToString(); 
    } 
    public static String GetPublicPropertiesAsString(this Object @this) 
    { 
     return GetMembersAsString(@this, @this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)); 
    } 

    public static String GetFieldsAsString(this Object @this) 
    { 
     return GetMembersAsString(@this, @this.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)); 
    } 
+0

Il peut supprimer le code dupant, mais il refactors aussi le code déclaratif original dans impératif, ce qui à mon humble avis réduit la lisibilité. –

+0

@Martin Eh bien, nous aurions pu conserver FP en passant dans les termes 'GetValue' pour chacun, mais pour être honnête (et en particulier sur les méthodes de mise en œuvre privées) je ne suis pas sûr que stressant sur FP vs autres est un débat vaut . Tant que cela fonctionne, etc .... –

Questions connexes