45

我正在寻找某种方法来有效地隐藏继承的成员。我有一个从公共基类继承的类库。一些较新的后代类继承了已退化的依赖属性,并且在使用IntelliSense或在可视化设计器中使用这些类时可能会有些混乱。

这些类都是为 WPF 或 Silverlight 2.0 编译而编写的控件。我知道ICustomTypeDescriptorand ICustomPropertyProvider,但我很确定它们不能在 Silverlight 中使用。

与其说是功能问题,不如说是可用性问题。我该怎么办?

更新

我真正想隐藏的一些属性来自不属于我自己的祖先,并且由于我正在设计的特定工具,我无法使用new操作员进行成员隐藏。(我知道,这很荒谬)

4

9 回答 9

37

像上面迈克尔建议的那样覆盖它们并防止人们使用覆盖的(sp?)方法,将它们标记为过时:

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

如果第二个参数设置为 true,如果有人尝试调用该方法并且第一个参数中的字符串是消息,则会生成编译器错误。如果 parm2 为 false,则只会生成编译器警告。

于 2008-08-04T20:14:30.547 回答
20

据我所知,虽然您无法阻止使用这些继承的成员,但您应该能够使用EditorBrowsableAttribute将它们从 IntelliSense 中隐藏起来:

Using System.ComponentModel;

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

编辑:刚刚在文档评论中看到了这一点,这使得它对此目的有点无用:

有一个突出的注释指出此属性“不会抑制同一程序集中的类中的成员”。这是真的,但并不完整。实际上,该属性不会在同一解决方案中抑制类中的成员。

于 2008-08-04T19:19:33.013 回答
14

您可以做的一件可能的事情是包含对象而不是从其他类扩展。这将在公开您想要公开的内容方面为您提供最大的灵活性,但如果您绝对需要该对象属于该类型,则它不是理想的解决方案(但是您可以从 getter 公开对象)。

因此:

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;
        }
    }
}
于 2008-08-04T19:22:48.903 回答
8

我认为你最好的最简单的方法是考虑组合而不是继承。

或者,您可以创建一个具有所需成员的接口,让您的派生类实现该接口,然后针对该接口进行编程。

于 2008-08-04T19:19:34.977 回答
4

我知道有几个答案,现在已经很老了,但最简单的方法就是将它们声明为new private.

考虑一个我目前正在处理的示例,其中我有一个 API,它使第 3 方 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 成为内部的,并且只公开我继承的类。

于 2010-12-08T20:54:44.970 回答
4

完全隐藏并标记不使用,包括智能感知,我相信这是大多数读者所期望的

[Obsolete("Not applicable in this class.")] 
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
于 2013-06-24T19:50:10.680 回答
1

我测试了所有建议的解决方案,它们并没有真正隐藏新成员。

但这一个可以:

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

但是在代码隐藏中它仍然可以访问,所以还要添加 Obsolete Attribute

[Obsolete("This property is not supported in this class", true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new string MyHiddenProperty
{ 
    get { return _myHiddenProperty; }
}
于 2012-05-23T10:19:32.310 回答
1

虽然上面明确指出,在 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;
      }
}

现在假设您想要 aclass 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属性公开的问题。

于 2019-10-11T15:30:28.987 回答
0

您可以使用接口

    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();
        }
    }
于 2017-11-13T00:24:00.833 回答