【问题标题】:Hiding inherited members隐藏继承的成员
【发布时间】:2010-09-05 07:36:41
【问题描述】:

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

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

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

更新

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

【问题讨论】:

    标签: c# wpf silverlight polymorphism dependency-properties


    【解决方案1】:

    像 Michael Suggests above 一样覆盖它们,并防止人们使用覆盖的 (sp?) 方法,将它们标记为过时:

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

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

    【讨论】:

    • 能不能不封也一样,效果一样?
    • @JamesM no obselete with true 阻止成员访问,sealed 阻止成员继承。因此,不能从密封类派生,并且密封方法允许覆盖其他类成员,但会阻止该成员被覆盖。 Sealed 不会阻止调用该类或成员,而 obselete 与 true 如果您尝试调用它会引发编译器错误。
    • @RobertPetz 使用过时的,它会给出警告,而不是错误。大不同。
    • @JamesM uhm...您是否阅读过您首先评论的答案?
    • @JamesM 大声笑我做到了,这就是为什么我回答了你原来的问题,指出为什么密封没有执行相同的任务。然后您注意到 Obselete 仅给出警告,这是不正确的,因为 true 的第二个参数会导致编译器错误而不是警告 - 正如您直接评论的答案所指出的那样。如果我误解了你,我欢迎澄清。这是MSDN source
    【解决方案2】:

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

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

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

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

    【讨论】:

      【解决方案3】:

      你可以做的一个潜在的事情是包含对象而不是从另一个类扩展。这将在公开您想要公开的内容方面为您提供最大的灵活性,但如果您绝对需要该类型的对象,它不是理想的解决方案(但是您可以从 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;
              }
          }
      }
      

      【讨论】:

        【解决方案4】:

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

        或者,您可以创建一个包含您想要的成员的接口,让您的派生类实现该接口,然后针对该接口进行编程。

        【讨论】:

          【解决方案5】:

          我知道有几个答案,现在已经很老了,但最简单的方法就是将它们声明为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 成为内部的,并且只公开我继承的类。

          【讨论】:

          • 如何将它用于依赖属性?
          【解决方案6】:

          完全隐藏并标记不使用,包括我认为大多数读者期望的智能感知

          [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】:

              虽然上面明确指出在 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 属性公开的问题。

              【讨论】:

                【解决方案9】:

                你可以使用接口

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

                【讨论】:

                  猜你喜欢
                  • 2012-02-13
                  • 2011-10-10
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多