如何使派生类中的只读属性可写?

我在C#基类上有一个枚举属性,我想在所有派生类上实现只读,除了一个(我需要在其上读写该属性) .

我的枚举声明如下:

enum Visibility { Public, Shared, Private }

(顺便说一句,枚举成员名称与C#可见性修饰符无关!)

最初我以为我能够在基类上声明属性,如下所示:

abstract class DataViewBase
{
    public Visibility Visibility { get; protected set; }
}

然后更改派生类的声明:

sealed class FooDataView : DataViewBase
{
    public Visibility Visibility { get; set; }
}

从而使setter公开,但我应该意识到这隐藏了基础 Visibility 属性并生成编译器警告 . 添加 new 关键字(即.2778871_)可以消除警告,但 FooDataView 上的属性实际上变成了一个全新的属性,与基类上的属性没有任何关联 . 因此,如果我这样做:

var foo = new FooDataView();
    foo.Visibility = Visibility.Shared;
    Console.WriteLine(foo.Visibility);  // Shared
    var casted = (DataViewBase) foo;
    Console.WriteLine(casted.Visibility);  // Public

两个 Visibility 属性值不同,这不是我想要的 .

我最终通过声明属性来解决这个问题:

sealed class FooDataView : DataViewBase
{
    public new Visibility Visibility
    {
        get { return base.Visibility; }
        set { base.Visibility = value; }
    }
}

这可确保保留两个 Visibility 属性"in-sync" .

然而,在完成所有这些之后,我想知道是否有另一种方法来完成我想要的东西(根据问题 Headers ),因为我的解决方案似乎有点不优雅 . 我想不出任何其他明显的解决方案 .

回答(3)

2 years ago

这两个怎么样:

1. Add A New Method

class FooDataView : DataViewBase
{
    public void ChangeVisibility(Visibility visibility)
    {
        Visibility = visibility;
    }
}

只需添加一个新的 ChangeVisibility() 方法 . 我认为这是最简单的 .

2. Use Interface:

public interface IDataView
{
    Visibility Visibility { get; }
}

public class DataView : IDataView
{
    public Visibility Visibility { get; set; }
}

public class PrivateDataView : IDataView
{
    public Visibility Visibility
    {
        get { return Visibility.Private; }
    }
}

我个人更喜欢第一种方法 .

2 years ago

然而,在完成所有这些之后,我想知道是否有另一种方法来完成我想要的东西(根据问题 Headers ),因为我的解决方案似乎有些不优雅 . 我想不出任何其他明显的解决方案 .

不,没有其他解决方案 . 为什么要将属性更改为可在派生类中公开设置(似乎setter在基类中也应该是公共的)?也许您应该以其他方式公开此功能 .

2 years ago

您可以创建一个访问setter的接口:

interface ISetVisibility {
    Visibility Visibilty {set;}
}

class MyDerived : MyBase, ISetVisibility {
    Visibility ISetVisibilty.Visibility { set {/* ... */ } }
}

现在在您的主类中,您可以使用以下内容:

((ISetVisibility) myDerived).Visibility = Visibilty.Shared;