interfaces no pueden contener campos, pero pueden contener propiedades. En la mayoría de los casos, las propiedades pueden ser utilizados como campos, y no hay ninguna dificultad en decir:
interface ISomeProperties
{int prop1 {get;set;}; string prop2 {get; set;}}
interface IMoreProperties
{string prop3 {get;set;}; double prop4 {get; set;}}
interface ICombinedProperties : ISomeProperties, IMoreProperties;
{ }
Dado un lugar de almacenamiento del tipo ICombinedProperties
, se puede acceder a todas las cuatro propiedades directamente y sin problemas.
Cabe señalar, sin embargo, que hay algunas cosas que se pueden hacer con los campos que no se pueden hacer con las propiedades. Por ejemplo, aunque un campo se puede pasar al Interlocked.Increment
, una propiedad no puede; intentar Interlocked.Increment
una propiedad copiándolo a una variable, llamando Interlocked.Increment
en eso, y luego copiar el resultado de nuevo a la propiedad podría "trabajo" en algunos casos, pero fallaría si dos hilos intentaron hacer lo mismo al mismo tiempo (que sería sea posible, por ejemplo para los dos hilos para leer un valor de 5, el incremento a 6, y luego escribir de nuevo 6, mientras que tiene dos hilos llaman Interlocked.Increment
en un campo que fue inicialmente igual a 5 estaría garantizado para producir 7.).
Para evitar esto, puede ser necesario tener la interfaz incluye algunos métodos que realizan un método entrelazado en un campo (por ejemplo, uno podría tener una función que llama al Interlocked.Increment
en el campo y devuelve el resultado) y/o incluir funciones que llamar a un delegado especificado con un campo como un parámetro ref
(por ejemplo
delegate void ActionByRef<T1>(ref T1 p1);
delegate void ActionByRef<T1,T2>(ref T1 p1, ref T2 p2);
delegate void ActionByRef<T1,T2,T3>(ref T1 p1, ref T2 p2, ref T3 p3);
interface IThing
{ // Must allow client code to work directly with a field of type T.
void ActOnThing(ActionByRef<T> proc);
void ActOnThing<ExtraT1>(ActionByRef<T, ExtraT1> proc, ref ExtraT1 ExtraP1);
void ActOnThing<ExtraT1, ExtraT2>
(ActionByRef<T> proc, ref ExtraT1 ExtraP1, ref ExtraT2 ExtraP2);
}
Dada una instancia de la interfaz, se podría hacer algo como:
theInstance.ActOnThing(
(ref int param) => Threading.Interlocked.Increment(ref param)
);
o, si uno tenía variables locales maskValue
y xorValue
y quería actualizar atómicamente el campo con field = (field & maskValue)^xorValue
:
theInstance.ActOnThing(
(ref int Param, ref int MaskValue, ref int XorValue) => {
int oldValue,newValue;
do {oldValue = param; newValue = (oldValue & MaskValue)^XorValue;
while (Threading.Interlocked.CompareExchange(ref Param, newValue, oldValue) !=
oldValue),
ref maskValue, ref xorValue);
);
Si había sólo unos pocos tipos de acciones que uno quiere realizar en los campos, sería más simple para incluir simplemente ellos dentro de la interfaz. Por otro lado, el enfoque dado anteriormente permite una interfaz para exponer sus campos de una manera tal como para permitir a los clientes realizar secuencias arbitrarias de acciones sobre ellos.
Puede usar la composición. También hay [mixins] (http://stackoverflow.com/questions/255553/is-it-possible-to-implement-mixins-in-c) –