2010-01-22 15 views
186

Por ejemplo, supongamos que quiero una interfaz ICar y que todas las implementaciones contendrán el campo Year. ¿Esto significa que cada implementación tiene que declarar por separado Year? ¿No sería mejor simplemente definir esto en la interfaz?¿Por qué las interfaces C# no pueden contener campos?

+18

Las interfaces no tienen implementación, para esto usan una clase abstracta, con la propiedad Año – PostMan

+5

Para agregar a lo que se ha dicho aquí, las interfaces son contratos, y un campo es un detalle de implementación en que define una ranura en la memoria de la máquina para poner un valor (ya sea escalar o puntero de dirección) en. – herzmeister

+3

Pero si el campo es público, es parte del contrato y no solo un detalle de implementación, ¿verdad? – Alex

Respuesta

198

Aunque muchas de las otras respuestas son correctas en el nivel semántico, me parece interesante abordar también este tipo de preguntas desde el nivel de detalles de la implementación.

Una interfaz puede ser pensado como una colección de ranuras, que contienen métodos. Cuando una clase implementa una interfaz, se requiere que la clase le diga al tiempo de ejecución cómo completar todos los espacios requeridos. Cuando usted dice

interface IFoo { void M(); } 
class Foo : IFoo { public void M() { ... } } 

la clase dice "cuando se crea una instancia de mí, cosas de una referencia a Foo.M en la ranura para IFoo.M.

A continuación, cuando se hace una llamada:

IFoo ifoo = new Foo(); 
ifoo.M(); 

el compilador genera un código que dice "pregunte al objeto qué método está en la ranura para IFoo.M, y llame a ese método.

Si una interfaz es una colección de ranuras que contienen métodos, algunas de esas ranuras también pueden contener los métodos get y set de una propiedad, los métodos get y set de un indexador, y los métodos add y remove de un evento. Pero un campo no es un método. No hay una "ranura" asociada a un campo que luego pueda "completar" con una referencia a la ubicación del campo. Y, por lo tanto, las interfaces pueden definir métodos, propiedades, indizadores y eventos, pero no campos.

+21

Lo que a veces echo de menos es una capacidad similar a la de Java para definir constantes de nivel de interfaz, que presumiblemente no requerirían un "espacio" para admitir en el idioma. – LBushkin

+2

Me gusta la explicación en palabras simples. Gracias. "CLR via C#" y "Essential .net volume 1" proporcionan más detalles. –

+4

¿Por qué un campo no tiene ranura? y la misma pregunta con los operadores? Recuerdo haber escuchado sobre el tipado de pato utilizando la reflexión para ver si se implementaba una interfaz, incluso si la clase no heredaba la interfaz. ¿Por qué no se puede usar el reflejo (o una ranura) para levantar un campo? Todavía estoy escribiendo mi código por lo que es posible que no necesite/desee campos, pero me sorprendió descubrir que no puedo usar operadores. los operadores son exactamente como los métodos de mi comprensión, excepto que no todos pueden sobrecargarse ('Una interfaz no puede contener constantes, campos, operadores'. De http://msdn.microsoft.com/en-us/library/ms173156.aspx) –

40

Declarar como una propiedad:

interface ICar { 
    int Year { get; set; } 
} 
+36

La pregunta es "** ¿Por qué ** no pueden las interfaces C# contener campos?". Esto no aborda eso. – AakashM

+3

Estoy de acuerdo con que esta respuesta no responde a la pregunta OP, pero bueno, resolvió mi problema. – Gorgen

18

¿Por qué no tienen una propiedad Year, que está perfectamente bien?

Las interfaces no contienen campos porque los campos representan una implementación específica de representación de datos, y exponerlos rompería la encapsulación. Por lo tanto, tener una interfaz con un campo codificaría efectivamente una implementación en lugar de una interfaz, ¡lo cual es una curiosa paradoja para una interfaz!

Por ejemplo, parte de su especificación Year podría requerir que sea válido para ICar ejecutores para permitir la asignación a una Year que es más tarde que el actual año + 1 o antes de 1900. No hay manera de decir que si había expuesto Year campos - es mejor utilizar las propiedades en su lugar para hacer el trabajo aquí.

0

Para esto puede tener una clase base de automóvil que implemente el campo de año, y todas las demás implementaciones pueden heredar de ella.

109

Las interfaces en C# están destinadas a definir el contrato que una clase cumplirá, no una implementación en particular.

En ese espíritu, C# interfaces de PERMITEN propiedades que se definen - que el llamante debe suministrar una implementación para:

interface ICar 
{ 
    int Year { get; set; } 
} 

clases que implementan pueden utilizar auto-propiedades para simplificar la implementación, si no hay lógica especial asociada con la propiedad:

class Automobile : ICar 
{ 
    public int Year { get; set; } // automatically implemented 
} 
+2

No es todo lo que es público como parte del contrato. Si una clase tiene un año público, ¿no dice que el contrato de clase tiene un campo de tipo Año para estar presente y accesible? –

+0

Tarde para la fiesta, pero no, en este caso significa que el contrato tiene un PROPIEDAD Año que se supone que debe implementar cualquier clase permanente. Las propiedades son en realidad métodos get/set, que tienen un campo de respaldo generado automáticamente si no se necesita una lógica especial. La sintaxis especial es solo para una notación más clara. – user3613916

+0

¿Cómo puedo definir un valor predeterminado constante (como 123) para esa implementación automática de 'Año'? – lama12345

13

La respuesta corta es sí, cada tipo de implementación tendrá que crear su propia variable de respaldo. Esto se debe a que una interfaz es análoga a un contrato. Todo lo que puede hacer es especificar trozos de código accesibles al público que un tipo de implementación debe poner a disposición; no puede contener ningún código en sí mismo.

Considere este escenario usando lo que ha sugerido:

public interface InterfaceOne 
{ 
    int myBackingVariable; 

    int MyProperty { get { return myBackingVariable; } } 
} 

public interface InterfaceTwo 
{ 
    int myBackingVariable; 

    int MyProperty { get { return myBackingVariable; } } 
} 

public class MyClass : InterfaceOne, InterfaceTwo { } 

Tenemos un par de problemas aquí:

  • Debido a que todos los miembros de una interfaz son - por definición - pública, nuestro respaldo la variable ahora está expuesta a cualquiera que use la interfaz
  • ¿Cuál myBackingVariable usará MyClass?

El enfoque más común es declarar la interfaz y una clase abstracta de barebones que la implementa. Esto le permite la flexibilidad de heredar de la clase abstracta y obtener la implementación de forma gratuita, o implementar explícitamente la interfaz y poder heredar de otra clase.Funciona de la siguiente manera:

public interface IMyInterface 
{ 
    int MyProperty { get; set; } 
} 

public abstract class MyInterfaceBase : IMyInterface 
{ 
    int myProperty; 

    public int MyProperty 
    { 
     get { return myProperty; } 
     set { myProperty = value; } 
    } 
} 
3

Las interfaces no incluyen ninguna implementación.

  1. Definir una interfaz con una propiedad.
  2. Además puede implementar esa interfaz en cualquier clase y usar esta clase en el futuro.
  3. Si es necesario, puede tener esta propiedad definida como virtual en la clase para que pueda modificar su comportamiento.
0

Una interfaz define propiedades y métodos de instancia públicas. Los campos suelen ser privados, o en el más protegido, internos o protegidos internos (el término "campo" no suele utilizarse para nada público).

Según lo declarado por otras respuestas, puede definir una clase base y definir una propiedad protegida a la que todos los herederos puedan acceder.

Una rareza es que una interfaz puede de hecho definirse como interna pero limita la utilidad de la interfaz, y normalmente se usa para definir la funcionalidad interna que no es utilizada por otro código externo.

32

Eric Lippert lo clavó, usaré una forma diferente de decir lo que dijo. Todos los miembros de una interfaz son virtuales y todos deben ser reemplazados por una clase que hereda la interfaz. No escribe explícitamente la palabra clave virtual en la declaración de interfaz, ni usa la palabra clave override en la clase, están implícitas.

La palabra clave virtual se implementa en .NET con métodos y una tabla v llamada, una matriz de punteros de método. La palabra clave override rellena el espacio de la tabla v con un puntero de método diferente, sobrescribiendo el que produce la clase base.Las propiedades, los eventos y los indexadores se implementan como métodos bajo el capó. Pero los campos no son. Las interfaces, por lo tanto, no pueden contener campos.

+0

Proporcionó el nombre técnico/real (v-table) al concepto de slots mencionado por Eric. Gracias por el detalle Hans. – RBT

5

Otros han dado el 'Por qué', así que solo agregaré que su interfaz puede definir un Control; si lo envuelve en una propiedad:

public interface IView { 
    Control Year { get; } 
} 


public Form : IView { 
    public Control Year { get { return uxYear; } } //numeric text box or whatever 
} 
2

Mucho se ha dicho, pero para hacerlo simple, aquí está mi opinión. Las interfaces están destinadas a tener contratos de método implementados por los consumidores o clases y no tener campos para almacenar valores.

Usted puede argumentar que entonces ¿por qué las propiedades están permitidas? Entonces, la respuesta simple es que las propiedades se definen internamente como solo métodos.

+1

Si necesita acceder a un miembro solo haga una propiedad y estará bien. – Unome

Cuestiones relacionadas