К сожалению, protected у члена интерфейса работает не так, как вы ожидаете.
Для члена интерфейса это несколько необычный модификатор, хотя спецификация C# (по крайней мере, черновик v8 (https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/basic-concepts.md#754-protected-access)) даёт некоторое объяснение:
Члены экземпляра интерфейса с доступностью protected или private protected недоступны из реализующих его классов и структур; доступ к ним имеют только производные от него интерфейсы.
Это различие важно для реализаций членов интерфейса по умолчанию. Например (параметр типа я убрал, поскольку здесь он ничего не меняет):
public interface IReading {
public float Adjustment { get; protected set; }
}
public interface IExtendedReading : IReading {
public float AdvanceAdjustment() => Adjustment++;
}
Явная реализация в конкретном классе позволяет не делать setter общедоступным, например с автоматически реализуемым свойством:
public class Reading : IReading {
float IReading.Adjustment { get; set; }
}
... либо с полной реализацией аксессоров:
public class Reading : IReading {
private float adjustment;
float IReading.Adjustment {
get => adjustment;
set => adjustment = value;
}
}
Тогда setter не будет общедоступен другим классам, но нужного вам поведения это всё равно не обеспечивает.
Здесь вместо интерфейса, возможно, лучше использовать абстрактный класс.
Переведено с английского·Показать оригиналUnfortunately, an interface member marked protected doesn't behave the way you're expecting.
That modifier is somewhat unusual on interface members, although the C# specification (the draft v8 text (https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/basic-concepts.md#754-protected-access), at least) offers some explanation:
Interface instance members whose accessibility is protected or private protected aren't accessible from its implementing classes or structs; only interfaces deriving from it may access them.
The distinction matters for default implementations of interface members. Here's an example (I've omitted the generic parameter because it doesn't affect this):
public interface IReading {
public float Adjustment { get; protected set; }
}
public interface IExtendedReading : IReading {
public float AdvanceAdjustment() => Adjustment++;
}
An explicit implementation in the concrete class lets you avoid exposing a publicly accessible setter, using either an auto-implemented property:
public class Reading : IReading {
float IReading.Adjustment { get; set; }
}
... or implementing the accessors in full:
public class Reading : IReading {
private float adjustment;
float IReading.Adjustment {
get => adjustment;
set => adjustment = value;
}
}
The setter then isn't exposed publicly to other classes, though this still doesn't achieve the behavior you're seeking.
An abstract class may be a better choice than an interface for this.