C#公共字段,只能从类中更新

时间:2013-06-07 12:37:47

标签: c# design-patterns access-modifiers

我有一个C#类,其中一个字段需要从类外部可见,但应该只在类中更改。但是,问题是该字段是通过公共mutator方法更新的,而不是直接(或由属性)更新:

public class FirstClass
{
    public SecondClass TheField {get; private set;}

    public FirstClass()
    {
        TheField = new SecondClass();
    }

    public void SomeMethod()
    {
        // ...
        TheField.Update(/*parameters*/);
        // ...
    }
}

public class SecondClass
{
    // some fields  

    public SecondClass() { }

    public void Update(/*parameters*/)
    {       
        // do something
    }
}

换句话说,我希望方法Update()只能从FirstClass中访问。

几种可能的解决方案以及我对它们不满意的原因:

  1. 使用setter而不是方法更改SecondClass。 - 不行,因为我需要有参数和很多东西要做。
  2. 将Update()设为内部而非公开。 - 仍然可以从组件内部访问,不够好。
  3. 从FirstClass修改SecondClass,即。将方法Update()移动到FirstClass,将其设为私有,并从SecondClass中公开所有需要的字段。 - 感觉不是很面向对象。
  4. 从SecondClass构造器调用Update()并在每次需要更新它时创建一个新的SecondClass实例。 - 性能会受到影响,因为SecondClass中有一些东西永远不会改变,我希望每次调用Update()时都要处理它。
  5. 有办法做到这一点吗?

5 个答案:

答案 0 :(得分:4)

@ aquaraga答案的基本实现,但改为使用接口:

public interface ISecond
{
    // some properties  
}

public class FirstClass
{
    private readonly SecondClass _TheField;
    public ISecond TheField { get { return _TheField; } }

    public FirstClass()
    {
        _TheField = new SecondClass();
    }

    public void SomeMethod()
    {
        // ...
        _TheField.Update(/*parameters*/);
        // ...
    }

    private class SecondClass : ISecond
    {
        // some properties  

        public void Update(/*parameters*/)
        {       
            // do something
        }
    }
}

基本上,公开一个包含所有可访问成员但没有Update方法的公共接口。使用一个私有嵌套类,它具有Update方法,但在调用代码时无法访问,并将其作为接口公开,而不是作为类。

一些示例用法:

FirstClass myFirst = ...
myFirst.SomeMethod(); //updates ok!
Console.WriteLine(myFirst.TheField.PropertyA); //can access properties of ISecond
myFirst.TheField.Update(); //compiler error!

有一点是你提到使用“某些领域”;作为一个接口,你将无法拥有字段而是属性。我不确定这对你来说是否是违规行为。

编辑:您提到了重用SecondClass并尽量减少代码重复的意图。一个快速解决方法可能是声明一些abstract类,protected Update方法,使用internal构造函数(因此其他程序集不能从中继承),然后公开{{1}用最小的实现调用:

Update

然后在你的public abstract class SecondClassBase : ISecond { // some properties internal SecondClassBase() { } protected void Update(/*parameters*/) { // do something } } 中,除嵌套类外没有任何变化:

FirstClass

仍有一些代码重复,但您现在需要做的就是复制/粘贴代码;无需为public class FirstClass { private readonly SecondClass _TheField; public ISecond TheField { get { return _TheField; } } public FirstClass() { _TheField = new SecondClass(); } public void SomeMethod() { // ... _TheField.Update(/*parameters*/); // ... } private class SecondClass : SecondClassBase { public new void Update(/*parameters*/) { base.Update(/*parameters*/); } } } 的每个实现重新声明属性或Update逻辑。您还可以将FirstClass方法重命名为其他方法以避免方法隐藏,但我想我会保留您之前使用的相同调用签名。

答案 1 :(得分:1)

一种方法是将一个名为UpdateableSecondClass的子类作为FirstClass的内部类。 它将继承自SecondClass,并且只有一个方法:Update()

您的SecondClass根本不应该使用Update()方法。你可以继续将它暴露给世界其他地方:

public SecondClass TheField {get; private set;}

答案 2 :(得分:1)

我认为你可以使用这种模式:

public partial class FirstClass {
    partial class ThirdClass: SecondClass {
        public void PerformUpdate(/* parameters */) {
            base.Update(/* parameters */);
        }
    }

    public void SomeMethod() {
    }

    public FirstClass() {
    }

    public SecondClass TheProperty {
        get {
            return m_TheField;
        }
    }

    ThirdClass m_TheField=new ThirdClass();
}

public partial class SecondClass {
    protected void Update(/* parameters */) {
    }

    public SecondClass() {
    }
}

ThirdClass继承自SecondClass,但未公开。该属性作为SecondClass类型的实例公开,但实际上是ThirdClass类型的字段。

方法SecondClass.Update仅暴露给派生类。您可以声明SecondClass公开,而不是嵌套,但保持对私有的更新。

答案 3 :(得分:0)

Nested Type

怎么样?
public class FirstClass
    {
        private SecondClass TheField { get; set; }

        public void SomeMethod()
        {
            TheField.Update( /*parameters*/);
        }

        private class SecondClass
        {
            public void Update( /*parameters*/)
            {
                // do something
            }
        }
    }

答案 4 :(得分:0)

Chris Sinclair回答很棒,这只是另一种选择

public sealed class FirstClass : SecondClass
{
    public FirstClass()
    {

    }

    public void SomeMethod(int j)
    {
        base.Update(j);
    }
}

public abstract class SecondClass
{

    public SecondClass() { }

    protected void Update(int i)
    {
        Console.WriteLine(i.ToString());
    }
}

这只是通过FirstClass

访问方法的部分