Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使只读属性在派生类中可写?_C#_Inheritance - Fatal编程技术网

C# 如何使只读属性在派生类中可写?

C# 如何使只读属性在派生类中可写?,c#,inheritance,C#,Inheritance,我在C#基类上有一个枚举属性,我希望该属性在所有派生类上都是只读的,但一个派生类除外(我需要该属性是读写的) 我的枚举声明如下: enum Visibility { Public, Shared, Private } (顺便说一下,枚举成员名称与C#可见性修饰符无关!) 最初我认为我可以在基类上声明属性,如下所示: abstract class DataViewBase { public Visibility Visibility { get; protected set; } }

我在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公开,但我应该意识到这会隐藏baseVisibility属性并生成编译器警告。添加
new
关键字(即
public new Visibility…
)可以消除警告,但是FooDataView上的属性实际上变成了一个全新的属性,与基类上的属性没有连接。因此,如果我这样做:

    var foo = new FooDataView();
    foo.Visibility = Visibility.Shared;
    Console.WriteLine(foo.Visibility);  // Shared
    var casted = (DataViewBase) foo;
    Console.WriteLine(casted.Visibility);  // Public
两个可见性属性值不同,这不是我想要的

我最终通过如下方式声明了财产,从而解决了这个问题:

sealed class FooDataView : DataViewBase
{
    public new Visibility Visibility
    {
        get { return base.Visibility; }
        set { base.Visibility = value; }
    }
}
这可确保两个可见性属性保持“同步”

然而,在完成了所有这些之后,我想知道是否有另一种方法可以实现我想要的(根据问题标题),因为我的解决方案似乎有些不雅观。我想不出任何其他明显的解决办法

然而,在完成所有这些之后,我想知道是否还有另外一个 实现我想要的方式(根据问题标题),给出 我的解决方案似乎有点不雅观。我想不出别的了 显而易见的解决办法


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

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

interface ISetVisibility {
    Visibility Visibilty {set;}
}

class MyDerived : MyBase, ISetVisibility {
    Visibility ISetVisibilty.Visibility { set {/* ... */ } }
}
现在,在主类中,您可以使用以下内容:

((ISetVisibility) myDerived).Visibility = Visibilty.Shared;
这两个怎么样:

1。添加新方法

class FooDataView : DataViewBase
{
    public void ChangeVisibility(Visibility visibility)
    {
        Visibility = visibility;
    }
}
只需添加一个新的
ChangeVisibility()
方法。我认为这是最简单的

2。使用界面:

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; }
    }
}

就我个人而言,我更喜欢第一种方法。

“更改派生类上的声明”-在.NET中,这通常是声明“全新”成员的同义词。您可以分别使用
virtual
override
关键字更改成员的行为(同时维护界面)。但是,在您的情况下,我会建议您自己最终会做什么,让所有类继承只读属性,并在您的一个特定类中使用可写属性来隐藏该属性。您可能希望自己添加一个答案,并在一段时间后将自己的答案标记为已接受。为什么要将该属性更改为可在派生类中公开设置:基本上,我的所有派生类型都有一个可见性属性很重要,因为我的代码通常处理基类。但是,只有一种派生类型应允许“最终用户”更改可见性;对于所有其他派生类型,可见性可能不同于基类(因此是受保护的setter),但本质上是硬编码的,并在创建对象时设置。我想我可以做的是在基类中创建一个公共虚拟getter/setter,在基类setter中引发一个异常,但是重写派生类中的getter/setter以使用它自己的私有支持字段。然而,我也在序列化这些对象,并且认为setter中的异常在反序列化时会造成麻烦。这确实有效,而且非常优雅。正如您在代码中所说明的,我能看到的唯一缺点是类的用户必须强制转换到接口才能设置属性值,您可能需要编辑您的答案以删除
public
access修饰符:它们不能在接口成员上声明,也不能在显式实现接口成员时声明。@StevenRands啊,谢谢,您是对的。我已经适当地更新了答案,我想第一种方法最有意义。对于类的用户来说,它归结为设置属性和调用方法之间的区别,我认为前者因其简单性而胜出。然而,在我看来,这两种方法都比任何需要转换到接口的方法更可取。是的,我同意。我也更喜欢第一种方法。我已经将其标记为已接受的答案,尽管事实上,发布的任何答案都会有效。我认为您的第一个解决方案(改变可见性的方法)对于“最终用户”来说是最容易使用的。