interfacce non possono contenere i campi, ma possono contenere le proprietà. Nella maggior parte dei casi, le proprietà possono essere usati come campi, e non v'è alcuna difficoltà con dire:
interface ISomeProperties
{int prop1 {get;set;}; string prop2 {get; set;}}
interface IMoreProperties
{string prop3 {get;set;}; double prop4 {get; set;}}
interface ICombinedProperties : ISomeProperties, IMoreProperties;
{ }
Data una posizione di tipo ICombinedProperties
stoccaggio, si può accedere a tutte e quattro le proprietà direttamente e senza alcun problema.
Va notato, tuttavia, che ci sono alcune cose che possono essere fatte con campi che non possono essere fatti con proprietà. Ad esempio, mentre un campo può essere passato a Interlocked.Increment
una proprietà non può; tentativo di Interlocked.Increment
una proprietà copiandolo a una variabile, chiamando Interlocked.Increment
su quello, e quindi copiare il risultato torna alla proprietà potrebbe "lavoro" in alcuni casi, ma fallirebbe se due thread tentato di fare la stessa cosa contemporaneamente (sarebbe essere possibile ad esempio che entrambi i thread leggano il valore 5, incrementarlo a 6 e quindi riscrivere 6, mentre avere due thread chiama Interlocked.Increment
su un campo che inizialmente era pari a 5 sarebbe garantito per ottenere 7.).
Per aggirare questo problema, potrebbe essere necessario che l'interfaccia includa alcuni metodi che eseguono un metodo interbloccato su un campo (ad esempio uno potrebbe avere una funzione che chiama Interlocked.Increment
sul campo e restituisce il risultato) e/o includere funzioni che richiederanno un delegato specificato con un campo come parametro ref
(es
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);
}
Dato un'istanza dell'interfaccia, si potrebbe fare qualcosa di simile:
theInstance.ActOnThing(
(ref int param) => Threading.Interlocked.Increment(ref param)
);
o, se uno avesse variabili locali maskValue
e xorValue
e volevano aggiornare atomicamente 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);
);
Se ci fossero solo pochi tipi di azioni che si possono desiderare per eseguire sui campi, sarebbe più semplice per includere semplicemente loro all'interno dell'interfaccia. D'altra parte, l'approccio sopra riportato consente a un'interfaccia di esporre i propri campi in modo tale da consentire ai client di eseguire sequenze arbitrarie di azioni su di essi.
È possibile utilizzare la composizione. C'è anche [mixins] (http://stackoverflow.com/questions/255553/is-it-possible-to-implement-mixins-in-c) –