2012-12-03 3 views
0

Je voudrais être en mesure de faire ce qui suit pour plusieurs classes:types génériques et l'héritage

var obj1 = new MyClass { Id = 1 }; 
var obj2 = new MyClass { Id = 2 }; 
obj1.Compare(obj2); 

J'ai fait la méthode d'extension suivante (inspired by a different question inhere):

public static class ObjExt 
{ 
    public static ICollection<string> Compare<T>(this T obj1, T obj2) 
    { 
     var properties = typeof(T).GetProperties(); 
     var changes = new List<string>(); 

     foreach (var pi in properties) 
     { 
      var value1 = typeof(T).GetProperty(pi.Name).GetValue(obj1, null); 
      var value2 = typeof(T).GetProperty(pi.Name).GetValue(obj2, null); 

      if (value1 != value2 && (value1 == null || !value1.Equals(value2))) 
      { 
       changes.Add(string.Format("Value of {0} changed from <{1}> to <{2}>.", pi.Name, value1, value2)); 
      } 
     } 
     return changes; 
    } 

Maintenant, cela fonctionne si Je fais une méthode dans toutes les classes que je veux comparer, donc je me suis dit que je le déplacerais donc une super classe pour DRY.

public class MyClass 
{ 
    public int Id { get; set; } 

    public ICollection<string> CompareMe<T>(T obj2) 
    { 
     return Compare<T>(obj2); 
    } 
} 

Si je déménage à une super classe, je reçois cette erreur de compilation:

Cannot convert instance type argument 'SuperClass' to 'T'

Si je le fais dans ma classe super:

return this.Compare<T>(obj2); 

je reçois une erreur de compilation en disant:

The type arguments for method 'Compare(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

Comment faire ceci gener ic dans une super classe?

+3

Peut-être que je ne comprends pas, mais si vous voulez déplacer votre méthode dans votre super classe pourquoi avez-vous besoin d'une méthode d'extension? –

+0

Bonne question! Et une solution encore meilleure. Je n'ai pas pensé à cela en refactoring. Je vous remercie! –

+0

Puis-je mettre un commentaire à jour pour le corriger? –

Répondre

1

Cette méthode d'extension:

public static bool GenericTest<T>(this T obj1, T obj2) 
{ 
} 

ne compile pas, parce que le compilateur n'a pas la moindre idée de ce que T est vraiment: il n'y a pas de contexte pour déduire les types de. Vous devez soit utiliser quelque chose comme where T: SuperClass ou modifier les paramètres de la méthode à this SuperClass obj1, SuperClass obj2.

+0

Cela a du sens, mais SuperClass est la seule classe capable d'utiliser la méthode d'extension. J'espérais le rendre plus générique si possible. Déplacer la méthode dans SuperClass a plus de sens (pour moi). –

1

Vous ne savez pas à quoi ressemble votre super classe. Mais cette compile bien:

public class SuperClass 
{ 
    public bool GenericTest<T>(T obj2) 
    { 
     return ObjExt.GenericTest(obj2, obj2); 
    } 
} 

public class MyClass : SuperClass 
{ 
    public int Id { get; set; } 

    public bool SuperTest<T>(T obj2) 
    { 
     return this.GenericTest<T>(obj2); 
    } 
} 

public static class ObjExt 
{ 
    public static bool GenericTest<T>(this T obj1, T obj2) 
    { 
     return true; 
    } 
} 
+0

GenericTest est dans une classe d'extension statique ObjExt - en dehors de MyClass et SuperClass. Cela semble changer l'image. –

+0

@NicolaiSchlenzig Vous écrivez _Je voudrais l'extraire à une super classe_. Donc, je ne vois pas comment cette méthode d'extension s'intègre dans l'image. – Magnus

+0

Vous avez raison. J'ai pensé que je pourrais garder ma méthode d'extension et l'appeler de ma super classe pour éviter le code redondant. –

1

Vous pouvez ajouter une contrainte générique sur la méthode SuperTest:

public bool SuperTest<T>(T obj2) where T: SuperClass 
      { 
       return this.GenericTest(obj2); 
      } 

et REPLACE T dans le extensionmethod avec SuperClass:

public static bool GenericTest(this SuperClass obj1, SuperClass obj2) 
     { 
      return true; 
     } 

Je ne sais pas si c'est ce que vous aviez en Mais attention.

+0

Je voulais le rendre aussi générique que possible - ne pas utiliser SuperClass dans l'extension du tout. J'ai pensé que je pourrais faire ceci en introduisant une méthode dans SuperClass appelant la méthode d'extension. –

+0

J'ai lu votre question mise à jour et compte tenu de votre mise en œuvre basée sur la réflexion, je ne vois pas pourquoi vous avez besoin de la méthode CompareMe du tout. Vous pouvez l'enlever et garder tout le reste. –

+0

C'est ce que j'ai conclu en lisant le commentaire de Matthew Nichols. Cependant, sa réponse a été supprimée, donc je ne pouvais pas la résoudre. –