Интерфейсы не могут содержать полей, но могут содержать свойства. В большинстве случаев свойства можно использовать как поля, и нетрудно сказать:
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