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
}
有更好的解决方案吗?
答案 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.。我看到了一些可能性。
S
是A
的一种吗?在这种情况下,继承可以帮助您,因为您可以通过protected
修饰符限制。
class A
{
public int x { get; protected set; }
}
class S : A
{
public A GetA() { return this; } //or something like that.
}
A
仅对S
有影响吗?在这种情况下,您可以将A
作为私有内部类S
,如Cloud9999Strife所示。
可能最好的是将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; }
}
}
从本质上讲,如果A
可以由一个泛型类修改,那么它可以在任何地方,除非A
和S
之间存在关联。这就是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的回答。