Однако я хотел бы пометить этот установщик как внутренний в интерфейсе, поэтому нет никаких шансов, что кто-то реализует ICustomer, а кто-то вне сборки изменит эти свойства. Есть ли хороший способ сделать это?
Нет. К сожалению, члены свойства всегда общедоступны. Кроме того, возня с уровнями доступа к свойствам, часть которых указана в интерфейсе, становится болезненной, IIRC. Что вы можете сделать, так это:
public interface ICustomer
{
string FirstName { get; }
string SecondName { get; }
}
internal interface ICustomerWithSetMethods : ICustomer
{
void SetFirstName(string name);
void SetLastName(string name);
}
public class Customer : ICustomerWithSetMethods
Тогда снаружи это будет выглядеть так, будто Customer
реализует только ICustomer
, но внутри ваш код увидит, что он реализует ICustomerWithSetMethods
.
К сожалению, это не очень хорошо работает, если вашему API нужно объявить какие-либо общедоступные методы, где вы действительно хотели бы просто объявить возвращаемый тип ICustomer
, но на самом деле вы будете знать, что это всегда ICustomerWithSetMethods
.
Предполагая, что вы все еще хотите разрешить несколько реализаций, вместо этого вы могли бы использовать абстрактный класс:
public abstract class CustomerBase
{
public abstract string FirstName { get; }
public abstract string LastName { get; }
internal abstract void SetFirstName(string name);
internal abstract void SetLastName(string name);
}
Теперь у нас есть небольшая странность, что никто за пределами сборки не может расширить ваш CustomerBase
, потому что есть абстрактные методы, которые им придется переопределить, и которые они даже не могут видеть, но это означает, что вы можете используйте CustomerBase
везде в вашем API.
Именно такой подход мы использовали в Noda Time для календарных систем в конце. Я записал об этом в блоге, когда впервые придумал план. Я обычно предпочитаю интерфейсы абстрактным классам, но здесь преимущество было значительным.
person
Jon Skeet
schedule
28.11.2012