Schnittstellen können Felder nicht enthalten, aber sie können Eigenschaften enthalten. In den meisten Fällen können Eigenschaften wie Felder verwendet werden, und es gibt keine Probleme mit den Worten:
interface ISomeProperties
{int prop1 {get;set;}; string prop2 {get; set;}}
interface IMoreProperties
{string prop3 {get;set;}; double prop4 {get; set;}}
interface ICombinedProperties : ISomeProperties, IMoreProperties;
{ }
ein Lagerort des Typs Gegeben ICombinedProperties
kann man alle vier Eigenschaften direkt und ohne viel Aufhebens zugreifen.
Es sollte jedoch beachtet werden, dass es einige Dinge gibt, die mit Feldern gemacht werden können, die mit Eigenschaften nicht gemacht werden können. Zum Beispiel, während ein Feld an Interlocked.Increment
übergeben werden kann, kann eine Eigenschaft nicht; Versuch, Interlocked.Increment
eine Eigenschaft durch Kopieren in eine Variable, Aufruf Interlocked.Increment
auf, und dann das Ergebnis in die Eigenschaft zurück kopieren "funktioniert" in einigen Fällen, würde aber fehlschlagen, wenn zwei Threads versuchten, das gleiche Ding gleichzeitig (es würde tun möglich sein, zB für beide Threads, einen Wert von 5 zu lesen, ihn auf 6 zu erhöhen und dann 6 zurückzuschreiben, während zwei Threads den Aufruf Interlocked.Increment
auf einem Feld haben, das anfänglich gleich 5 war, würde garantiert 7 ergeben.
Um dies zu umgehen, kann es notwendig sein, dass die Schnittstelle einige Methoden enthält, die eine verblockte Methode für ein Feld ausführen (z. B. könnte eine Funktion Interlocked.Increment
auf dem Feld aufrufen und das Ergebnis zurückgeben) und/oder beinhalten Funktionen, die einen bestimmten Delegierten mit einem Feld als ref
Parameter (zB
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);
}
Gegeben eine Instanz der Schnittstelle aufrufen wird, ein etwas wie tun könnte:
theInstance.ActOnThing(
(ref int param) => Threading.Interlocked.Increment(ref param)
);
oder, wenn man lokale Variablen hatte maskValue
und xorValue
und wollte atomar, um das Feld aktualisieren mit 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);
);
Wenn es nur wenige Arten von Aktionen wäre, würde man auf den Feldern ausführen wollen, wäre es am einfachsten sein, einfach schließen sie innerhalb der Schnittstelle. Auf der anderen Seite erlaubt der oben gegebene Ansatz einer Schnittstelle, ihre Felder so zu exponieren, dass Clients willkürliche Abfolgen von Aktionen auf ihnen ausführen können.
Sie können Zusammensetzung verwenden. Es gibt auch [Mixins] (http://stackoverflow.com/questions/255553/is-it-possible-to-implement-mixins-in-c) –