Подтвердить что ты не робот

Как я могу скрыть общедоступное свойство базового класса в производном классе

Я хочу скрыть базовое публичное свойство (элемент данных) в моем производном классе:

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
{

}

У меня есть член как открытый, потому что я хочу, чтобы член наследовался в классе c, но хотите скрыть элемент в классе b, как я могу это сделать?

У меня есть возможность выборочно унаследовать переменную, которую я хочу в моем базовом классе??? Это действительно плохо, я думаю, что ms должен предоставить нам опцию (может быть модификатором) для выполнения этого


Edit:

Я сам нашел ответ (я слышал, что многие из них говорят, что это невозможно в С#, но вы можете это сделать)

Я включаю код, если он полезен

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

Ответ 1

Я попытаюсь объяснить примерами, почему это плохая идея, а не использование загадочных терминов.

Ваше предложение было бы иметь код, который выглядит так:

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, но не может сказать, что - это может быть очевидно глядя на фрагмент кода, но более сложные сценарии делают его практически невозможным).

Таким образом, компилятор в большом проценте случаев не сможет дать ошибку компилятора, что Item1 фактически недоступен. Таким образом, это исключает возможность проверки времени выполнения. Когда вы пытаетесь установить Item1 на объект, который на самом деле имеет тип WithHidden, он выдает исключение.

Теперь, обращаясь к любому члену, любое свойство в любом непечатаемом классе (который является большинством из них) может вызывать исключение, потому что это фактически производный класс, который скрывал член. Любая библиотека, которая предоставляет любые незапечатанные типы, должна была бы писать защитный код при доступе к любому члену только потому, что кто-то мог его скрыть.

Потенциальным решением этого является запись функции, так что только те элементы, которые объявляют себя скрытыми, могут быть скрыты. Затем компилятор запрещает любой доступ к скрытому члену на переменные этого типа (время компиляции), а также включает проверки выполнения, чтобы исключить исключение FieldAccessException, если оно было передано базовому типу и пыталось получить доступ к этому (время выполнения).

Но даже если разработчики С# действительно столкнулись с огромными проблемами и расходами на эту функцию (помните, что функции дороги, особенно в дизайне языка), необходимо защищать защитный код, чтобы избежать проблем с потенциальными исключениями FieldAccessExceptions, поэтому какое преимущество перед реорганизацией вашей иерархии наследования вы получили? С помощью функции сокрытия нового элемента было бы огромное количество потенциальных мест для ошибок в ползучести в вашем приложении и библиотеках, что увеличивало время разработки и тестирования.

Ответ 2

То, что вы хотите сделать, напрямую связано с зерном OO, вы не можете "отменить публикацию", поскольку это нарушает принцип замещения. Вы должны реорганизовать это во что-то еще.

Ответ 3

Единственное, о чем я могу думать, это сделать item1 виртуальным в классе a:

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

}

а затем переопределить его в классе b, но выведите исключение в getter и setter. Кроме того, если это свойство используется в визуальном дизайнере, вы можете использовать Browsable attribute для отображения.

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

Ответ 4

Ответ Вадима напомнил мне о том, как MS добивается этого в рамках Рамок в определенных местах. Общая стратегия состоит в том, чтобы скрыть участника из Intellisense, используя атрибут EditorBrowsable. (NB Это только скрывает его, если оно находится в другой сборке). Хотя это не мешает кому-либо использовать этот атрибут, и они могут видеть его, если они отбрасывают базовый тип (см. Мое предыдущее объяснение), это делает его гораздо менее уязвимым, поскольку он не отображается в Intellisense и сохраняет класс интерфейса чистым.

Его следует использовать экономно, хотя, если другие варианты, такие как реструктуризация иерархии наследования, сделают его намного более сложным. Это последнее средство, а не первое решение, о котором можно подумать.

Ответ 5

Если вы используете интерфейс вместо базового класса для определения свойства, вы можете реализовать свойство явно. Для использования этого свойства требуется явное приведение к интерфейсу.

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

public class MyClass : IMyInterface
{

    string IMyInterface.Name { get; set; }

}

Вы можете найти более здесь.

Ответ 6

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

Ответ 7

В первую очередь это нехорошо, если вы используете некоторые методы, которые управляют базовым классом.
Вы можете попытаться использовать устаревший аргумент, чтобы пользователи дважды думали использовать это свойство.

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

Ответ 8

То, что вы описываете, является чем-то вроде "частного наследования" из С++ и недоступно в С#.

Ответ 9

Вы не можете сделать это напрямую, но вы можете переопределить свойства в дочернем классе и сделать их только для чтения, например.

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
{

}

Ответ 10

Вы можете использовать интерфейсы, чтобы скрыть свойство. В дочернем классе был реализован интерфейс, у которого не было свойства, тогда он не появится.

Вам понадобится два интерфейса для того, когда вы захотите этого свойства, и когда вы этого не сделаете, тем самым сделайте его ужасным взломом.

Ответ 11

Изменение доступности виртуального участника является наследующим классом, специально запрещенным спецификацией языка С#:

Объявление переопределения и переопределенный базовый метод имеют одинаковые объявленная доступность. Другими словами, объявление переопределения не может измените доступность виртуального метода. Однако, если переопределенный базовый метод защищен внутренним и объявлен в другая сборка, чем сборка, содержащая метод переопределения то должны быть защищены переопределяемые методы объявленной доступности.

Из раздела 10.6.4 Методы переопределения

Те же правила, которые применяются к методу переопределения, также применяются к свойствам, поэтому переход от public в private путем наследования из базового класса не может быть выполнен на С#.

Ответ 12

Если вы хотите скрыть участника из базового класса, вам нужно будет добавить новый базовый класс, позвоните ему baseA, и ваш код должен выглядеть следующим образом:

программа класса   {       static void Main (string [] args)       {           b obj = new b();           obj.item1 = 4;//должен показывать ошибку, но это действие?       }   }

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

class b : baseA
{        
}

class c : a
{
}

Ответ 13

На самом деле вам нужны интерфейсы:

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

Затем просто передайте интерфейсы. Если классы должны использовать общую реализацию, поместите это в третий класс и пусть они получаются из этого класса, а также реализуют их соответствующий интерфейс.

Ответ 14

Да, это возможно. Что скажете вы в делегации. Я попытаюсь дать представление о том, что называется "делегирование" в ООП с фрагментом кода:

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

Ответ 15

Вы можете переопределить его, а затем Добавить тег [Browsable (false)], чтобы не показывать его в дизайнере.

Простой:

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