16

我正在尝试找出解决此问题的好方法。我有一个实现 ICustomer 接口的 Customer 类。这个接口有很多属性:

public interface ICustomer
{

   string FirstName {get; set;}
   string LastName  {get; set;}
}

但是,我只希望某些类能够设置这些属性;即项目中的那些类。所以我想制作二传手internal

public class Customer : ICustomer
{

   string FirstName {get; internal set;}
   string LastName  {get; internal set;}
}

但是,我想将该设置器标记为接口中的内部,因此不可能有人实现 ICustomer 并且程序集之外的人修改这些属性。有没有好的方法来做到这一点?

4

2 回答 2

24

接口中的属性应该是只读的。实现接口的具体类有一个setter是可以接受的,即使接口中没有定义。

public interface ICustomer
{
   string FirstName { get; }
   string LastName  { get; }
}

public class Customer : ICustomer
{
   public string FirstName { get; internal set; }
   public string LastName  { get; internal set; }
}

如果通过接口公开设置器真的很重要,而不是让接口完全只读,你可以使用这样的东西:

public interface IReadCustomer
{
    string FirstName { get; }
    string LastName { get; }
}

internal interface IWriteCustomer
{
    string FirstName { set; }
    string LastName { set; }
}

internal interface IReadWriteCustomer : IReadCustomer, IWriteCustomer
{ }

public class Customer : IReadWriteCustomer
{
    private string _firstName;
    private string _lastName;

    public string FirstName
    {
        get { return _firstName; }
        internal set { _firstName = value; }
    }
    public string LastName
    {
        get { return _lastName; }
        internal set { _lastName = value; }
    }

    string IReadCustomer.FirstName
    {
        get { return FirstName; }
    }

    string IReadCustomer.LastName
    {
        get { return LastName; }
    }

    string IWriteCustomer.FirstName
    {
        set { FirstName = value; }
    }

    string IWriteCustomer.LastName
    {
        set { LastName = value; }
    }
}
于 2012-11-28T20:58:07.063 回答
7

但是,我想将该设置器标记为接口中的内部,因此不可能有人实现 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只是 implements ICustomer,但从内部你的代码会看到它 implements 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.

这就是我们在Noda Time中最终为日历系统采用的方法——当我第一次想出这个计划时,我在博客上写过它。通常更喜欢接口而不是抽象类,但这里的好处是显着的。

于 2012-11-28T20:59:15.300 回答