Скрытие унаследованных членов

Я ищу способ эффективно скрыть унаследованные члены. У меня есть библиотека классов, которые наследуются от общих базовых классов. Некоторые из более поздних классов-потомков наследуют свойства зависимостей, которые стали рудиментарными и могут немного сбивать с толку при использовании IntelliSense или использовании классов в визуальном конструкторе.

Все эти классы представляют собой элементы управления, написанные для компиляции либо для WPF, либо для Silverlight 2.0. Я знаю о ICustomTypeDescriptor и ICustomPropertyProvider, но уверен, что их нельзя использовать в Silverlight.

Это не столько функциональная проблема, сколько проблема удобства использования. Что я должен делать?

Обновлять

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

Ответов (9)

Решение

Переопределите их, как предлагает Майкл выше, и чтобы люди не могли использовать переопределенные (sp?) Методы, пометьте их как устаревшие:

[Obsolete("These are not supported in this class.", true)]
public override  void dontcallmeanymore()
{
}

Если для второго параметра установлено значение true, будет сгенерирована ошибка компилятора, если кто-либо попытается вызвать этот метод, а строка в первом параметре является сообщением. Если параметр parm2 ложен, будет сгенерировано только предупреждение компилятора.

Я думаю, что лучший наименее хакерский способ - рассматривать композицию, а не наследование.

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

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

Таким образом:

public class MyClass : BaseClass
{
    // Your stuff here
}

Становится:

public class MyClass
{
    private BaseClass baseClass;

    public void ExposeThisMethod()
    {
        baseClass.ExposeThisMethod();
    }
}

Или:

public class MyClass
{
    private BaseClass baseClass;

    public BaseClass BaseClass
    {
        get
        {
            return baseClass;
        }
    }
}

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

Но этот ДЕЙСТВИТЕЛЬНО:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new string MyHiddenProperty
{ 
    get { return _myHiddenProperty; }
}

Но в коде он все еще доступен, поэтому добавьте также устаревший атрибут

[Obsolete("This property is not supported in this class", true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new string MyHiddenProperty
{ 
    get { return _myHiddenProperty; }
}

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

[Obsolete("Not applicable in this class.")] 
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]

Вы можете использовать интерфейс

    public static void Main()
    {
        NoRemoveList<string> testList = ListFactory<string>.NewList();

        testList.Add(" this is ok ");

        // not ok
        //testList.RemoveAt(0);
    }

    public interface NoRemoveList<T>
    {
        T this[int index] { get; }
        int Count { get; }
        void Add(T item);
    }

    public class ListFactory<T>
    {
        private class HiddenList: List<T>, NoRemoveList<T>
        {
            // no access outside
        }

        public static NoRemoveList<T> NewList()
        {
            return new HiddenList();
        }
    }

Хотя выше ясно сказано, что в C# невозможно изменить модификаторы доступа для унаследованных методов и свойств, я решил эту проблему с помощью своего рода «поддельного наследования» с использованием неявного преобразования типов.

Пример:

public class A
{
      int var1;
      int var2;

      public A(int var1, int var2)
      {
            this.var1 = var1;
            this.var2 = var2;
      }
      public void Method1(int i)
      {
            var1 = i;
      }
      public int Method2()
      {
            return var1+var2;
      }
}

Теперь предположим, что вы хотите class B наследовать class A, но хотите изменить некоторые возможности доступа или даже полностью изменить Method1.

public class B
{
      private A parent;

      public B(int var1, int var2)
      {
            parent = new A(var1, var2);
      } 

      int var1 
      {
            get {return this.parent.var1;}
      }
      int var2 
      {
            get {return this.parent.var2;}
            set {this.parent.var2 = value;}
      }

      public Method1(int i)
      {
            this.parent.Method1(i*i);
      }
      private Method2()
      {
            this.parent.Method2();
      }


      public static implicit operator A(B b)
      {
            return b.parent;
      }
}

Включая неявное приведение в конце, он позволяет нам обрабатывать B объекты как A s, когда нам нужно. Также может быть полезно определить неявное приведение из A->B .

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

Примечание:

Хотя это позволяет изменять доступность public свойств, это не решает проблему protected публикации свойств.

Хотя, насколько мне известно, вы не можете предотвратить использование этих унаследованных членов, вы должны иметь возможность скрыть их от IntelliSense с помощью EditorBrowsableAttribute :

Using System.ComponentModel;

[EditorBrowsable(EditorBrowsableState.Never)]
private string MyHiddenString = "Muahahahahahahahaha";

Изменить: только что видел это в комментариях к документации, что делает его бесполезным для этой цели:

Существует заметное примечание, в котором говорится, что этот атрибут «не подавляет членов класса в той же сборке». Это правда, но не полностью. На самом деле атрибут не подавляет членов класса в том же решении.

Я знаю, что на этот вопрос было несколько ответов, и сейчас он довольно старый, но самый простой способ сделать это - просто объявить их как new private .

Рассмотрим пример, над которым я сейчас работаю, где у меня есть API, который делает доступными все методы сторонней библиотеки DLL. Мне нужно использовать их методы, но я хочу использовать свойство .Net вместо методов getThisValue и setThisValue. Итак, я создаю второй класс, наследую первый, создаю свойство, использующее методы get и set, а затем переопределяю исходные методы get и set как частные. Они по-прежнему доступны для всех, кто хочет создать на них что-то другое, но если они просто хотят использовать движок, который я создаю, они смогут использовать свойства вместо методов.

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

public class APIClass
{
    private static const string DllName = "external.dll";

    [DllImport(DllName)]
    public extern unsafe uint external_setSomething(int x, uint y);

    [DllImport(DllName)]
    public extern unsafe uint external_getSomething(int x, uint* y);

    public enum valueEnum
    {
        On = 0x01000000;
        Off = 0x00000000;
        OnWithOptions = 0x01010000;
        OffWithOptions = 0x00010000;
    }
}

public class APIUsageClass : APIClass
{
    public int Identifier;
    private APIClass m_internalInstance = new APIClass();

    public valueEnum Something
    {
        get
        {
            unsafe
            {
                valueEnum y;
                fixed (valueEnum* yPtr = &y)
                {
                    m_internalInstance.external_getSomething(Identifier, yPtr);
                }
                return y;
            }
        }
        set
        {
            m_internalInstance.external_setSomething(Identifier, value);
        }
    }

    new private uint external_setSomething(int x, float y) { return 0; }
    new private unsafe uint external_getSomething(int x, float* y) { return 0; }
}

Теперь valueEnum доступен для обоих классов, но в классе APIUsageClass отображается только свойство. Класс APIClass по-прежнему доступен для людей, которые хотят расширить исходный API или использовать его по-другому, а APIUsageClass доступен для тех, кто хочет чего-то более простого.

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