Интерфейсите не могат да съдържат полета, но могат да съдържат свойства. В повечето случаи свойствата могат да се използват като полета и не е трудно да се каже:
interface ISomeProperties
{int prop1 {get;set;}; string prop2 {get; set;}}
interface IMoreProperties
{string prop3 {get;set;}; double prop4 {get; set;}}
interface ICombinedProperties : ISomeProperties, IMoreProperties;
{ }
Като се има предвид място за съхранение от тип ICombinedProperties
, човек може да получи достъп до всичките четири свойства директно и без суетене.
Трябва да се отбележи обаче, че има няколко неща, които могат да се правят с полета, които не могат да се правят със свойства. Например, докато поле може да бъде предадено на Interlocked.Increment
, свойство не може; опитът за Interlocked.Increment
свойство чрез копирането му в променлива, извикването на Interlocked.Increment
върху това и след това копирането на резултата обратно в свойството може да "работи" в някои случаи, но ще се провали, ако две нишки се опитат да направят едно и също нещо едновременно (би е възможно, например и двете нишки да прочетат стойност 5, да я увеличат до 6 и след това да запишат обратно 6, докато две нишки извикват Interlocked.Increment
на поле, което първоначално е било равно на 5, гарантирано ще даде 7.).
За да се заобиколи това, може да е необходимо интерфейсът да включва някои методи, които или изпълняват взаимосвързан метод на поле (например може да има функция, която извиква Interlocked.Increment
на полето и връща резултата) и/или включва функции, които ще извикване на определен делегат с поле като параметър ref
(напр.
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);
}
Като се има предвид екземпляр на интерфейса, човек може да направи нещо като:
theInstance.ActOnThing(
(ref int param) => Threading.Interlocked.Increment(ref param)
);
или, ако имаше локални променливи maskValue
и xorValue
и искаше атомно да актуализира полето с 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);
);
Ако имаше само няколко вида действия, които човек би искал да извърши върху полетата, най-лесно би било просто да ги включите в интерфейса. От друга страна, подходът, даден по-горе, позволява на интерфейса да изложи своите полета по такъв начин, че да позволи на клиентите да извършват произволни последователности от действия върху тях.
person
supercat
schedule
06.08.2012