C#中的内部属性设置器

lar*_*ryq 12 c# setter properties internal

我正在试图找到一个很好的方法来解决这个问题.我有一个Customer类,它实现了ICustomer接口.该界面中包含许多属性:

public interface ICustomer
{

   string FirstName {get; set;}
   string LastName  {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

我只希望某些类能够设置这些属性; 即项目中的那些课程.所以我考虑制作二传手internal:

public class Customer : ICustomer
{

   string FirstName {get; internal set;}
   string LastName  {get; internal set;}
}
Run Code Online (Sandbox Code Playgroud)

我想将该setter标记为接口内部,因此不可能有人实现ICustomer,并且程序集之外的人修改这些属性.有没有办法做到这一点?

Ser*_*rvy 20

界面中的属性应该是只读的.即使接口中没有定义set接口,实现接口的具体类也可以接受.

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; }
}
Run Code Online (Sandbox Code Playgroud)

如果通过接口公开setter非常重要,而不是让接口完全是只读的,那么你可以使用这样的东西:

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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @larryq这就是重点,因为接口没有提交给setter.如果要实现第二个内部接口,可以添加setter.我经常有一系列接口:这是一个真实的例子:`IDimensionedMap`只提交到2D实体的维度; `IReadMap`具有可读属性,`IReadMap:IDimensionedMap`用于只读或计算映射,然后是`IWriteMap:IReadMap`.但这是一个复杂的可扩展实用程序类系列.(如果你好奇,这些是2d希尔伯特空间,而不是字典.) (2认同)

Jon*_*eet 6

我想将该setter标记为接口内部,因此不可能有人实现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
Run Code Online (Sandbox Code Playgroud)

然后从外部看起来它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);
}
Run Code Online (Sandbox Code Playgroud)

现在我们有一点点奇怪的是,程序集之外没有人可以扩展你的CustomerBase,因为有些抽象方法他们不得不覆盖它们甚至看不到 - 但它确实意味着你可以CustomerBase在你的API中使用.

这是我们最终在Noda Time中为日历系统采用的方法 - 当我第一次提出计划时,我在博客上写了这篇文章.我通常更喜欢接口来抽象类,但这里的好处是显着的.