2010-01-09 11 views
7

(C#, VS2008) En un programa en el que estoy trabajando, tengo muchos objetos que tienen una ID e implementan IComparable, por lo que la lista <> -s de los diversos objetos se puede buscar fácilmente por ID. Desde odio código de copiar/pegar, pensé que sería abstracto que poco de funcionalidad a una clase base, así:¿Cómo hacer una clase base abstracta IComparable que no compare dos clases heredadas por separado?

using System; 

namespace MyProg.Logic 
{ 
    abstract class IDObject : IComparable<IDObject> 
    { 
     private int miID; 

     public int ID 
     { 
      get { return miID; } 
      set { miID = value; } 
     } 

     public IDObject(int ID) 
     { 
      miID = ID; 
     } 

     #region IComparable<IDObject> Members 

     int IComparable<IDObject>.CompareTo(IDObject other) 
     { 
      return miID.CompareTo(other.miID); 
     } 

     #endregion 
    } 
} 

El inconveniente que veo a esto es que dos clases separadas que heredan cada uno lo haría ser directamente comparable usando .CompareTo() y esperaba hacer cumplir que cada clase que hereda de IDObject es solo comparable a otras de la misma clase. Así que estaba esperando a encontrar la manera de hacer eso y se acercó con esta

using System; 

namespace MyProg.Logic 
{ 
    abstract class IDObject : IComparable<T> where T : IDObject 
    { 
     private int miID; 

     public int ID 
     { 
      get { return miID; } 
      set { miID = value; } 
     } 

     public IDObject(int ID) 
     { 
      miID = ID; 
     } 

     #region IComparable<T> Members 

     int IComparable<T>.CompareTo(T other) 
     { 
      return miID.CompareTo(other.miID); 
     } 

     #endregion 
    } 
} 

Pero eso da un error de compilación de "Las restricciones no son permitidos en las declaraciones no genéricos"

mirarlo, I Estoy seguro de que hay una manera de hacer algo así para que cada clase solo sea comparable a otras instancias de la misma clase, pero no puedo desentrañar la sintaxis.

Respuesta

12

Puede usar el Curiously Recurring Template Pattern para resolver este problema.

abstract class Base<T> : IComparable<T> where T : Base<T> { 
    public int Rank { get; set; } // Order instances of derived type T by Rank 
    public int CompareTo(T other) { return Rank.CompareTo(other.Rank); } 
} 
class Foo : Base<Foo> {} 
class Bar : Base<Bar> {} 

static class Program { 
    static void Main() { 
     var foo1 = new Foo { Rank = 1 }; 
     var foo2 = new Foo { Rank = 2 }; 
     var bar1 = new Bar { Rank = 1 }; 
     var bar2 = new Bar { Rank = 2 }; 

     Console.WriteLine(foo1.CompareTo(foo2)); 
     Console.WriteLine(bar2.CompareTo(bar1)); 

     //error CS1503: Argument '1': cannot convert from 'Bar' to 'Foo' 
     //Console.WriteLine(foo1.CompareTo(bar1)); 
    } 
} 
2

creo que tienes problemas más grandes que simplemente asegurarse de que los tipos de clases de derivados son los mismos. También está cargando la clase derivada con la responsabilidad de generar un único ID. Eso requiere que la clase derivada sepa qué otras identificaciones se asignaron previamente. Siendo realistas, eso requiere una fábrica de clases. Deberá hacer cumplir eso haciendo que el constructor de su clase abstracta esté protegido.

No es muy práctico. Si la identificación es solo un número opaco que establece la identidad del objeto, considere asignarle la identificación usted mismo. Use un miembro estático para realizar un seguimiento del último asignado. Ahora se vuelve simple, y ya no tiene que preocuparse por los tipos de clase derivados.

+0

+1. Buen punto. He actualizado mi respuesta para mostrar el patrón sin tener que resolver el problema de ID. –

+0

Los identificadores provienen de una columna SQLite DB Integer Primary Key - Por lo tanto, garantizados por SQLite para ser únicos entre un tipo de objeto, pero dos objetos de diferentes tipos podrían superponerse, por lo tanto, limitar el IComparable a solo miembros de la misma clase. – Drogo

Cuestiones relacionadas