簡體   English   中英

如何在派生類中隱藏基類公共屬性

[英]How can I hide a base class public property in the derived class

我想在我的派生類中隱藏基本公共屬性(數據成員):

class Program
{
    static void Main(string[] args)
    {
        b obj = new b();
        obj.item1 = 4;// should show an error but it doent ???
    }
}

class a
{
    public int item1 {get; set;}
    public int item2 { get; set; }
}

class b : a
{
    new private int item1;
}

class c : a
{

}

我有一個 public 成員,因為我希望成員在 c 類中被繼承,但想隱藏 b 類中的成員,我該怎么做?

我沒有選擇在我的基類中選擇性地繼承我想要的變量嗎??? 那真的很糟糕,我認為 ms 應該為我們提供一個選項(可能是一個修飾符)來執行此操作


編輯:

我自己找到了答案(我聽到很多人說這在 c# 中是不可能的,但你可以這樣做)

我包括代碼以防它有用

class Program
{
    static void Main(string[] args)
    {
        b obj = new b();
        obj.item1 = 4; // shows an error  : )
    }
}

class a
{
    public int item1 { get; set; }
    public int item2 { get; set; }
}

class b : a
{
    new public static int item1
    {
        get;
        private set;
    }
}

我將嘗試用例子來解釋為什么這是一個壞主意,而不是使用神秘的術語。

您的建議是使用如下所示的代碼:

public class Base
{
    public int Item1 { get; set; }
    public int Item2 { get; set; }
}


public class WithHidden : Base
{
    hide Item1; // Assuming some new feature "hide" in C#
}

public class WithoutHidden : Base { }

這將使以下代碼無效:

WithHidden a = new WithHidden();
a.Item1 = 10; // Invalid - cannot access property Item1
int i = a.Item1; // Invalid - cannot access property Item1

而這正是你想要的。 但是,假設我們現在有以下代碼:

Base withHidden = new WithHidden();
Base withoutHidden = new WithoutHidden();

SetItem1(withHidden);
SetItem1(withoutHidden);

public void SetItem1(Base base)
{
    base.Item1 = 10;
}

編譯器不知道 SetItem1 中的參數 base 將是什么運行時類型,只知道它至少是 Base 類型(或從 Base 派生的某種類型,但它無法分辨是哪種類型——查看代碼片段,但更復雜的場景使其幾乎不可能)。

因此,在大部分情況下,編譯器將無法給出 Item1 實際上無法訪問的編譯器錯誤。 所以這就留下了運行時檢查的可能性。 當您嘗試在實際上是 WithHidden 類型的對象上設置 Item1 時,它會引發異常。

現在訪問任何成員,任何非密封類(大多數)上的任何屬性都可能引發異常,因為它實際上是隱藏該成員的派生類。 任何暴露任何非密封類型的庫在訪問任何成員時都必須編寫防御性代碼,因為有人可能隱藏了它。

一個潛在的解決方案是編寫該功能,以便只有聲明自己可隱藏的成員才能隱藏。 然后,編譯器將禁止對該類型變量的任何隱藏成員的訪問(編譯時),並且還包括運行時檢查,以便在將 FieldAccessException 強制轉換為基類型並嘗試從中訪問(運行時)時拋出 FieldAccessException .

但是即使 C# 開發人員確實為此功能付出了巨大的麻煩和代價(記住,功能是昂貴的,尤其是在語言設計中)仍然需要編寫防御性代碼來避免拋出潛在的 FieldAccessExceptions 的問題,那么有什么優勢呢?重組您的繼承層次結構您獲得了嗎? 使用新的成員隱藏功能,將有大量潛在的錯誤可以潛入您的應用程序和庫,從而增加開發和測試時間。

您想要做的事情直接違背了 OO 的原則,您不能“取消發布”成員,因為這違反了替換原則。 您必須將其重構為其他內容。

Vadim 的回應讓我想起了 MS 如何在某些地方的框架中實現這一點。 一般策略是使用EditorBrowsable 屬性對Intellisense 隱藏成員。 (注意,如果它在另一個程序集中,這只會隱藏它)雖然它不會阻止任何人使用該屬性,並且如果他們轉換為基本類型,他們可以看到它(請參閱我之前的解釋)它使它更不容易被發現不會出現在 Intellisense 中並保持類的界面干凈。

它應該謹慎,雖然可以使用,只有當像重組繼承層次其他的選擇會使它復雜得多 這是最后的手段,而不是第一個想到的解決方案。

如果您使用接口而不是基類來定義屬性,則可以顯式實現該屬性。 需要對接口進行顯式轉換才能使用該屬性。

public interface IMyInterface
{
    string Name { get; set; }
}

public class MyClass : IMyInterface
{

    string IMyInterface.Name { get; set; }

}

您可以 在此處找到更多 信息

我唯一能想到的就是在 a 類中將 item1 設為虛擬:

class a
{
    public virtual int item1 { get; set; }
    public int item2 { get; set; }

}

然后在 b 類中覆蓋它,但在 getter 和 setter 中拋出異常。 此外,如果在可視化設計器中使用此屬性,您可以使用Browsable 屬性不顯示。

class b : a
{
    [Browsable(false)]
    public override int item1
    {
        get
        {
            throw new NotSupportedException();
        }
        set
        {
            throw new NotSupportedException();
        }
    }
}

首先,如果您使用某些操作基類的方法,這不是一個好主意。
您可以嘗試使用過時的參數讓用戶三思而后行。

[System.Obsolete("Do not use this property",true)]  
public override YourType YourProperty { get; set; }

您可以覆蓋它,然后添加 [Browsable(false)] 標簽以防止在設計器中顯示它。

簡單的:

public class a:TextBox
{
        [Browsable(false)]
        public override string Text
        {
            get { return ""; }
            set { }
        }
}

您所描述的內容類似於 C++ 中的“私有繼承”,並且在 C# 中不可用。

您不能直接執行此操作,但您可以覆蓋子類中的屬性並使它們只讀,例如

class Program
{
    static void Main(string[] args)
    {
        b obj = new b();
        obj.item1 = 4;// should show an error but it doent ???
    }
}

class a
{
    public virtual int item1 {get; set;}
    public virtual int item2 { get; set; }

}

class b : a
{
    public override int item1
    { 
         get { return base.item1; }
         set { }
    }
}

    class c : a
{

}

您可以使用接口來隱藏該屬性。 子類將實現一個沒有屬性的接口,然后它就不會出現。

您需要兩個接口,分別用於何時需要該屬性和何時不需要該屬性,從而使其成為一個可怕的黑客。

更改虛擬成員的可訪問性是 C# 語言規范明確禁止的繼承類:

覆蓋聲明和覆蓋的基方法具有相同的聲明可訪問性。 換句話說,覆蓋聲明不能改變虛方法的可訪問性。 但是,如果重寫的基方法是受保護的內部方法,並且它是在與包含重寫方法的程序集不同的程序集中聲明的,則必須保護重寫方法聲明的可訪問性。

來自 10.6.4 節覆蓋方法

適用於覆蓋方法的相同規則也適用於屬性,因此無法在 C# 中通過從基類繼承來實現從publicprivate

如果你想從基類中隱藏一個成員,那么你需要添加一個新的基類,我們稱之為 baseA,你的代碼應該如下:

class Program
{
    static void Main(string[] args)
    {
        b obj = new b();
        obj.item1 = 4;// should show an error but it doent ???
    }
}

class baseA
{
    public int item2 { get; set; }
}
class a:baseA
{
    public int item1 { get; set; }        
}

class b : baseA { }

class c : a { }

你真正需要的是接口:

    public interface ProvidesItem1
    {
        int item1 { get; set; }
    }

    public interface ProvidesItem2
    {
        int item2 { get; set; }
    }

    class a : ProvidesItem1, ProvidesItem2
    {
        public int item1 { get; set; }
        public int item2 { get; set; }
    }

    class b : ProvidesItem1
    {
        public int item1 { get; set; }
    }

然后只需傳遞接口。 如果類應該使用公共實現,請將其放在第三個類中,讓它們從該類派生並實現各自的接口。

對的,這是可能的。 你對代表團怎么說。 我將嘗試通過一段代碼來了解 OOP 中所謂的“委托”:

public class ClassA
{
    // public
    public virtual int MyProperty { get; set; }

    // protected
    protected virtual int MyProperty2 { get; set; }
}

public class ClassB
{
    protected ClassC MyClassC;

    public ClassB()
    {
        MyClassC = new ClassC();
    }

    protected int MyProperty2
    {
        get { return MyClassC.MyProperty2; }
        set { MyClassC.MyProperty2 = value; }
    }

    protected int MyProperty
    {
        get { return MyClassC.MyProperty; }
        set { MyClassC.MyProperty = value; }
    }

    protected class ClassC : ClassA
    {
        public new int MyProperty2
        {
            get { return base.MyProperty2; }
            set { base.MyProperty2 = value; }
        }

        public override int MyProperty
        {
            get { return base.MyProperty; }
            set { base.MyProperty = value; }
        }
    }
}
namespace PropertyTest    
{    
    class a
    {    
        int nVal;

        public virtual int PropVal
        {
            get
            {
                return nVal;
            }
            set
            {
                nVal = value;
            }
        }
    }

    class b : a
    {
        public new int PropVal
        {
            get
            {
                return base.PropVal;
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            a objA = new a();
            objA.PropVal = 1;

            Console.WriteLine(objA.PropVal);

            b objB = new b();
            objB.PropVal = 10; // ERROR! Can't set PropVal using B class obj. 
            Console.Read();
        }
    }
}

您可以使用new修改器。

樣本;

public class Duck
{
    public string Color{get; set;}
    public void Swim() { }
}
public class DonaldDuck : Duck
{
    new public void Swim() 
    { 
        /*you could call in DonaldDuck.Swim  only here but not public for DonaldDuck client.*/ 
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM