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

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

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

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

Обновить

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

4.08.2008 19:13:54
9 ОТВЕТОВ
РЕШЕНИЕ

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

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

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

35
23.05.2017 12:24:42
Не можете ли вы также запечатать это с тем же эффектом?
James M 19.01.2017 16:51:57
@JamesM не устарел с истинным, запрещает доступ к элементу , запечатанный предотвращает наследование члена . Таким образом, запечатанный класс не может быть получен из, и запечатанный метод позволяет другим членам класса быть переопределенными, но предотвращает переопределение этого члена. Sealed не препятствует вызову этого класса или члена, в то время как устаревшее значение true выдает ошибку компилятора, если вы пытаетесь вызвать его.
Robert Petz 25.05.2017 15:31:26
@RobertPetz при использовании устаревшего, выдает предупреждение, а не ошибку. Большая разница.
James M 25.05.2017 15:48:41
@JamesM хм ... ты вообще читал ответ, который ты буквально прокомментировал первым?
Robert Petz 25.05.2017 19:02:23
@JamesM lol Я так и сделал, поэтому я ответил на ваш первоначальный вопрос, отметив, почему запечатывание не выполняет ту же задачу. Тогда вы заметили, что Obseleteвыдает только предупреждение, которое неверно, так как второй аргумент trueвызывает ошибку компилятора, а не предупреждение - как ответ, который вы прямо прокомментировали для конкретных состояний. Если я вас неправильно понимаю, я приветствую разъяснения. Вот источник MSDN
Robert Petz 25.05.2017 23:43:42

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

Using System.ComponentModel;

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

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

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

17
19.11.2009 17:51:07

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

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

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;
        }
    }
}
13
4.08.2008 19:22:48

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

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

8
4.08.2008 19:19:34

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

3
8.12.2010 21:27:06
Как можно использовать это для свойств зависимости?
James M 24.12.2017 06:02:06

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

[Obsolete("Not applicable in this class.")] 
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
3
24.06.2013 19:50:10

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

Но этот делает:

[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; }
}
1
21.10.2012 11:56:57

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

    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();
        }
    }
0
13.11.2017 00:24:00

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

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

Примечание:

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

0
11.10.2019 15:30:28