【问题标题】:Accessing protected members of another class访问另一个类的受保护成员
【发布时间】:2012-05-09 15:29:27
【问题描述】:

我有一个类 A,我需要从中访问类 B 的受保护成员,就像在 C++ 中使用friend关键字一样。但是,内部修饰符不适合我的需要。 B 类需要创建 A 类的实例,修改其私有数据,并返回对该类的引用。这些 A 类成员需要对原始调用者保持私密。

public class A
{
    protected int x;
}

public class B
{
    public static A CreateClassA()
    {
        A x = new A();
        x.x = 5;   // ERROR : No privilege
        return x;
    }
}

【问题讨论】:

  • 试过重新设计你的自我摆脱那个噩梦吗?

标签: c# class friend access-modifiers


【解决方案1】:

这个问题在这一点上有点老了,但这是另一种方法,按照你的要求做,不用讲课或摇手指:

考虑:

A foo = new A();
FieldInfo privateField = foo.GetType().GetField("x", BindingFlags.NonPublic | BindingFlags.Instance);
privateField.SetValue(foo, 5);

警告:使用上述代码会破坏封装,弯曲您的脊椎,并且可能会因 OO 纯粹主义者的尖锐尖叫而导致耳朵损伤。

...但它对工厂类非常有用,弥补了 C# 缺少朋友关键字的问题。

警告 2:这很慢。

【讨论】:

    【解决方案2】:

    您可以使用protected internal 而不是internal 来授予对同一程序集中的所有类以及其他程序集中的子类的访问权限:

    public class A
    {
        protected internal int x;
    }
    
    public class B
    {
        public static A CreateClassA()
        {
            A x = new A();
            x.x = 5;   // hurray
            return x;
        }
    }
    

    【讨论】:

      【解决方案3】:

      您需要为protected 字段创建一个公共设置器或从该类继承。

      public class A
      {
          protected int x;
      
          public int X { set { x = value; }  }
      }
      
      public static A CreateClassA()
      {
          A x = new A();
          x.X = 5;
          return x;
      }
      

      或者:

      public class B : A
      {
          public static A CreateClassA()
          {
              this.x = 5; 
              return x;
          }
      }
      

      【讨论】:

      • 它是一个字段,而不是一个属性:setter 不适用
      • @MarcGravell - 是的,我的错误。但是为该字段添加一个公共设置器应该没问题,不是吗?
      • 这会起作用,但是出于所有实际目的,您将该字段变成了公共字段。
      • @zmbq - 这可能正是 OP 正在寻找的(字段值无法在类及其继承者之外读取)。
      • 第二个块没有编译
      【解决方案4】:

      您应该查看官方的 MSDN Friend Assembly。 http://msdn.microsoft.com/en-us/library/0tke9fxk.aspx 通过那个例子,你可以这样做:

      using System.Runtime.CompilerServices;
      using System;
      
      [assembly: InternalsVisibleTo("AssemblyB")]
      public sealed class A
      {
          internal int x;
      }
      

      并从程序集 B 设置/调用内部方法/字段。

      【讨论】:

        【解决方案5】:

        试试这个:

           public class A
           {
              protected int x;
        
              public class B
              {
                  public static A CreateClassA()
                  {
                      A x = new A();
                      x.x = 5;   // ERROR : No privilege
                      return x;
                  }
              }
           }
        

        【讨论】:

        • 每个创建的 A 类都会存在一个 B 类吗?
        • 没有,只要它是静态的。如果我错了,请纠正我。我使用这种类来构建复杂的对象。就像是。 SomeObject.Builder().DoSomething()。其中 SomeObject = A,Builder = B,DoSomething = CreateClassA
        • 如果您只留下“公共 B 类”部分怎么办?所以 A 类包含一个“公共静态 A CreateClassA()”(这不是一个好名字,它创建了 A 类的一个实例,而不是 A 类本身)。我想这也可以解决问题
        • 这取决于对象的复杂程度。如果只有一个字段,那么静态工厂方法就可以了。但是当你有几个组件的变体时,一个类是更好的选择。
        • 我认为在实例化 B 类之前不会创建它。我在没有静态修饰符的情况下使用它,当您需要访问 A 受保护(甚至私有)成员,而不在 A 中公开具体方法/属性时。就像从 A 扩展,但您只需要在需要时创建 B .
        【解决方案6】:

        如果您从 A 继承,您只能访问受保护的成员。您现在可以:

        • 从 A 继承
        • 创建一个设置 X 值的公共方法 setX(int newX)。

        【讨论】:

        • 这就是我的想法,但是调用者可以使用公共 Set() 方法可能会破坏 A 类的功能,因为它本质上是只读数据。从我使用它的角度来看,继承没有任何意义,我希望这不是唯一的选择。
        • 如果您希望该字段表现不可变,请将构造函数添加到将其作为参数接收的类 A。
        • 这个不错。这样,x 只能从 A 类家族之外设置一次。请注意,从 A 继承的类在创建 A 的实例后仍然能够更改值。
        【解决方案7】:

        其他选择:

        public class A
        {
            public A() { }
        
            public A(int x)
            {
                this.x = x;
            }
        
            protected int x;
        }
        
        public class B
        {
            public static A CreateClassA()
            {
                A x = new A(5);
                return x;
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-07-22
          • 2017-08-01
          • 2016-10-01
          • 2014-06-07
          • 1970-01-01
          • 2014-02-22
          相关资源
          最近更新 更多