C#类成员访问问题

时间:2013-11-26 09:11:39

标签: c# access-modifiers

class A
{
    public int x { get; set; }
    // other properties
}

class S
{
    public A GetA(...);
}

我想做出以下限制:
A只能在S内进行修改。当其他人通过A获得GetA()时,他只能获取A的属性,而不能修改它们。

我决定在S中创建一个返回另一个对象的新函数:

class B
{
    A a;
    public int x { get { return a.x; } }
    // replicate other A's properties
}

有更好的解决方案吗?

5 个答案:

答案 0 :(得分:7)

你可以创建A的界面,只定义了getter,并从GetA返回:

public interface IA
{
   int x { get; }
}

class A : IA
{
    public int x { get; set; } // nothing stopping you having a setter on the class
}

class S
{
    private A a = new A(); // you can call the setter internally on this instance
    public IA GetA(){ return a; } // when someone gets this thy only get the getter
}

当然,没有什么可以阻止某人将GetA的结果投射到A,然后他们就有了制定者 - 但是你真的无能为力!

答案 1 :(得分:1)

也许嵌套类也可以满足您的需求?

public class S
{
    private A ClassA { get; set; }

    public S()
    {
        ClassA = new A();
    }

    private class A
    {
        public int TestProperty { get; set; }
    }

    public int GetClassATestProperty
    {
        get
        {
            return this.ClassA.TestProperty;
        }
    }
}

答案 2 :(得分:1)

在C ++中,您可以使用friend关键字。 And there is no equivalent in C# sadly.。我看到了一些可能性。

  1. SA的一种吗?在这种情况下,继承可以帮助您,因为您可以通过protected修饰符限制。

    class A
    {
        public int x { get; protected set; }
    }
    
    class S : A
    {
        public A GetA() { return this; } //or something like that.
    }
    
  2. A仅对S有影响吗?在这种情况下,您可以将A作为私有内部类S,如Cloud9999Strife所示。

  3. 可能最好的是A留作公众的抽象类或接口,并将其嵌套在具体的实现中S - Jamiec和Cloud9999Strife的答案组合。

    public abstract class A // or interface
    {
       public abstract int x { get; }
    }
    
    class S
    {
        public A GetA() { return AImplInstead(); }
    
        class AImpl : A
        {
            // nothing stopping you having a setter on the class
            public override int x { get; set; } 
        }
    }
    
  4. 从本质上讲,如果A可以由一个泛型类修改,那么它可以在任何地方,除非AS之间存在关联。这就是C#的设计方式。现在我们所能做的就是让最终用户难以(即修改A)。公开界面是其中的一部分。嵌套使其更深一层。请注意,无论如何,还有反射将打破所有封装..

答案 3 :(得分:0)

您可以更改A的实现,以便引入只读模式。创建实例后,您可以根据需要设置属性。一旦有人获得实例,您就可以启用只读模式。在只读模式下,setter应抛出异常,例如InvalidOperationException异常。为了避免大量if (IsReadOnly) ...;语句,您可以使用策略模式来更改实例的行为 根据您的需要,您还可以在调用者请求对象时创建一个激活ReadOnly模式的副本。即使在第一次请求实例后,这也允许更改 这在界面上的优点是调用者不能使用强制转换来获得对setter的访问。虽然您不必实现接口,但是只读模式的实现应该是值得的。这取决于您对风险和损害的分析。

答案 4 :(得分:-1)

另一种选择是返回A的副本,而不是A本身。

class S
{
    public A GetA() { return a.Clone(); }
}

你也可以使A成为一个结构,这会导致这种情况自动发生。 这当然取决于A的大小或复杂程度。在大多数情况下,界面可能会更好,详见Jamiec的回答。