아쉽지만 인터페이스 멤버의 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으로 노출하지 않을 수 있습니다. 자동 구현 속성을 쓸 수도 있고요:
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가 public으로 노출되지는 않지만, 그래도 원하시는 동작을 달성하는 것은 아닙니다.
이 경우에는 인터페이스보다 추상 클래스가 더 나을 수 있습니다.
영어에서 번역·원문 보기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.