1

我有一个 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() 时都想处理它。

有没有办法做到这一点?

4

5 回答 5

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构造函数(因此其他程序集不能从它继承),然后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。您也可以将new Update方法重命名为其他名称以避免隐藏方法,但我想我会保留与您之前相同的调用签名。

于 2013-06-07T12:51:17.610 回答
1

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

SecondClass根本不应该有这个Update()方法。您可以继续将其暴露给世界其他地方:

public SecondClass TheField {get; private set;}
于 2013-06-07T12:43:24.910 回答
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但未公开。该属性作为 type 的实例公开SecondClass,但实际上是 type 的字段ThirdClass

该方法SecondClass.Update仅对派生类公开。您可以声明SecondClass公共的,而不是嵌套的,但将归档的更新保持为私有。

于 2013-06-07T13:09:02.740 回答
0

嵌套类型怎么样。

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

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

        private class SecondClass
        {
            public void Update( /*parameters*/)
            {
                // do something
            }
        }
    }
于 2013-06-07T12:45:53.000 回答
0

克里斯辛克莱的回答很棒,这只是另一种选择

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 访问方法的一部分

于 2013-06-07T17:15:49.243 回答