C#如何覆盖公共成员并将其变为私有成员

13

可能吗?您能将任何东西的访问权限更改为其他任何东西吗?


5
我每天至少会写出那个拼写错误。 - Phil Gan
1
@Phil:不,依我看,楼主拼写正确。;) - Yuck
哇,直到它被修复之后我才注意到。 - Mark Lalor
3
简短回答是:不行。但这可能意味着代码存在“设计或实现的问题”。请提供一个代码示例并描述您需要这样做的原因。 - Menefee
1
我有一个用户控件,但像 RightToLeft 这样的一些属性在现有情况下根本没有意义。 - Mark Lalor
@Menefee:这种情况经常发生:数组实现了IList<T>但是没有办法实现Add或者Remove方法;socket是一个stream,但是你无法在其上执行seek操作。 - Gabe
3个回答

18
不,你可以使用一个私有方法来隐藏公共成员变量,但是你不能在子类中使用一个私有成员变量覆盖公共成员变量。实际上,并不仅仅是公共和私有的问题,这适用于限制访问权限的所有情况。
更改后:通过使用更严格的访问权限(例如此处的私有访问权限)来隐藏变量,您仍将在基类或子类引用中看到基类成员变量,但当新的访问级别可用时,它会转向新的方法。
因此,通常情况下,当您进行隐藏时,隐藏仅在其访问级别上可见时才起作用。否则,将使用原始方法。
public class BaseClass
{
    public virtual void A() { }

    public virtual void B() { }
}

public class SubClass
{
    // COMPILER ERROR, can't override to be more restrictive access
    private override void A() { }

    // LEGAL, you can HIDE the base class method, but which is chosen 
    // depends on level accessed from
    private new void B() { }
}

所以SubClass.B()仅在可访问时隐藏基类方法。也就是说,如果你在SubClass中调用SubClass.B(),它将采用被隐藏的B()形式,但由于B()是私有的,它对自身外部的类不可见,因此他们仍然看到BaseClass.B()
简而言之:
1)你不能覆盖一个方法使其更加限制(访问方面)。 2)你可以使用一个更加限制的方法来隐藏一个方法,但它只有在新的访问类型可见时才有效,否则基础方法仍然存在。
public class BaseClass
{
    public virtual void A() { }
    public virtual void B() { }
}

public class SubClass : BaseClass
{
    public virtual void A() { B(); }

    // legal, you can do this and B() is now hidden internally in SubClass,
    // but to outside world BaseClass's B() is still the one used.
    private new void B() { }
}

// ...

SubClass sc = new SubClass();
BaseClass bc = new BaseClass();

// both of these call BaseClass.B() because we are outside of class and can't
// see the hide SubClass.B().
sc.B();
bc.B();

// this calls SubClass.A(), which WILL call SubClass.B() because the hide
// SubClass.B() is visible within SubClass, and thus the hide hides BaseClass.B()
// for any calls inside of SubClass.
sc.A();

你确定吗?看起来似乎会违反 Liskov 的原则。 - Rag
你可以这样做。不过,你可以将它强制转换为“BaseClass”,然后像什么都没有发生一样调用该方法。 - Femaref
@Brian:是的,隐藏以使其更加严格是允许的。编译正常。请记住,该方法仍然存在,并且只要您将其视为基类引用,它仍然存在并运行,只是从子类中不可见(在私有隐藏的情况下)。并不是说这总是最好的选择,从面向对象的角度来看,但在C#中是可能的。 - James Michael Hare
@Femaref:确切地说,或者当然可以通过基类引用访问。 - James Michael Hare
哦,从你回答的主要内容中看,我不知为何认为你是在说你示例代码中标记为“非法”的那个是合法的。 - Rag

4

不行。

通常处理这种情况的方式是抛出NotImplementedException或类似的异常。


6
"NotImplementedException" 意味着某些事情被错误地省略了。 "NotSupportedException" 意味着某些事情是有意而为之被省略的(并且可能仍然是错误的,具体情况而定)。 - Anthony Pegram

2

您无法缩小或扩大重写成员的可见性。但是,您可以使用new关键字定义另一个方法,该方法可以为您提供具有相同名称但在多态性方面不兼容的新方法。

public class A : B
{
    public new void Foo()
    {
        base.Foo();
    }
}

2
这不是一个重写(over ride),而是一个覆盖(over write)。如果将该类转换为 B,则即使在 A 中覆盖了该方法,它也将可用。 - Femaref

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接