c#公共字段,只能从类内部更新

本文关键字:内部 更新 字段 | 更新日期: 2023-09-27 18:17:19

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

有办法做到这一点吗?

c#公共字段,只能从类内部更新

@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!

有一点是你提到使用"some fields";作为一个接口,你不能有字段,只能有属性。我不确定这对你来说是否是个坏消息。

编辑:您提到您打算重用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*/);
        }
    }
}

仍然有一些代码重复,但你现在需要做的就是复制/粘贴代码;不需要为FirstClass的每个实现重新声明属性或Update逻辑。您还可以将new Update方法重命名为其他内容以避免方法隐藏,但我认为我会保留您之前使用的相同调用签名。

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

你的SecondClass不应该有Update()方法。你可以继续向世界其他地方展示它:

public SecondClass TheField {get; private set;}

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

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声明为公共的,而不是嵌套的,但是保持对文件的更新为私有的。

如何使用嵌套类型

public class FirstClass
    {
        private SecondClass TheField { get; set; }
        public void SomeMethod()
        {
            TheField.Update( /*parameters*/);
        }
        private class SecondClass
        {
            public void Update( /*parameters*/)
            {
                // do something
            }
        }
    }

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

访问方法的一部分