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

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

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

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

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

Обновление

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

Using System.ComponentModel;

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

Я знаю, что на это было несколько ответов, и это довольно старый, но самый простой способ сделать это - просто объявить их как 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 внутренним и только выставить мой унаследованный класс.

Ответ 6

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

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

Ответ 7

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

Но это одно:

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

Ответ 8

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

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

Ответ 9

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

Пример:

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, когда это необходимо. Также может быть полезно определить неявное приведение из A->B.

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

Примечание:

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