【问题标题】:Make method accessible only to other class使方法只能被其他类访问
【发布时间】:2017-01-11 13:53:37
【问题描述】:

我有两个班级,SensorChannel。它们通过在通道中“插入”传感器来使用(即,使用Sensor 实例设置ChannelSensor 属性)。然后,当您使用非空传感器在Channel 中调用AddSamples 时,将通知Sensor.WhenNewSamples 的订阅者:

public abstract class Channel
{
    public Sensor Sensor { get; set; }

    public abstract void AddSamples(IEnumerable<double> samples)
}

public abstract class Sensor
{
    public abstract IObservable<double> WhenNewSamples { get; }

    internal abstract void AddSamples(IEnumerable<double> samples);
}

我想要实现的是一种在内部传递这些样本的方法,而不必创建暴露的Sensor.AddSamples。此外,当然,它应该与在其他程序集中定义的子类一起使用,因为 SensorChannel 是抽象的,并且在域模型库中定义。

更新:

以下实现可以,但它无法编译,因为Sensor.AddSamples 是内部的,而派生类在其他程序集中:

public class ConcreteChannel : Channel
{
    public override void AddSamples(IEnumerable<double> samples)
    {
        // AddSamples below is inaccessible
        Sensor.AddSamples(samples);
    }
}

public class ConcreteSensor : Sensor
{
    Subject<double> _subject = new Subject<double>();

    public override IObservable<double> WhenNewSamples
    {
        get { return _subject.AsObservable(); }
    }

    // "No suitable method found to override"
    internal override void AddSamples(IEnumerable<double> samples)
    {
        samples.ToList().ForEach(s => _subject.OnNext(s));
    }
}

【问题讨论】:

  • 使AddSamples 受保护?然后它只对派生类可见。还是我理解错了?
  • @HimBromBeere 我希望 Channel.AddSamples 公开,但我不知道如何封装从 ChannelChannel.Sensor 的数据传递,而不创建公开的 Sensor.AddSamples,我想避免。我正在寻找一种“魔术隧道”,我只能在一个类中添加样本,并且它会在另一个类中弹出,前提是它们彼此“连接”(即,Channel.Sensor 属性已设置到Sensor 的一个实例)。查看我的更新。
  • 如果您需要从类和程序集外部访问成员,那么它应该是public。没有办法解决这个问题。
  • 您是否尝试将 AddSamples 声明为“受保护的内部”?您甚至可以在另一个程序集中创建的子类中继承它。
  • @ChetanRanpariya 这仍然不会提供从ConcreteChannel 中访问该成员的权限。

标签: c# access-modifiers


【解决方案1】:

我发现我将太多的实现细节委托给子类,因此一种可能的解决方案是使用模板方法设计模式,同时使用三种不同的方法:

  • 一个是模板方法:一个受保护的抽象方法,应该由子类充实;
  • 其他是实现“业务逻辑”的内部非虚拟方法:从内部方法对受保护模板方法的调用
  • 某个“外部”类中的公共方法,将调用转发到“内部”类中的内部方法。

这样,我得到以下调用堆栈:

  1. 我在客户端程序集中定义的外部子类中调用了一个公共方法;
  2. 该方法实际上是在核心组件的基类中实现的,并且在核心组件中也从内部基类调用内部方法;
  3. 客户端基类内部方法调用受保护模板方法,由客户端程序集内部子类实现。

我测试过,它可以工作,所以这里是代码:

核心组件:

public abstract class Channel
{
    // inner class is a property of outer class
    public Sensor Sensor { get; set; }

    // Public method in outer class calls internal method in inner class
    public void AddSamples(IEnumerable<double> samples)
    {
        Sensor?.AddSamplesInternal(samples);
    }
}

public abstract class Sensor
{
    // domain specific property exposing the effects of template method
    public abstract IObservable<double> WhenNewSamples { get; }

    // internal method forwards the call to a protected abstract "template" method
    internal void AddSamplesInternal(IEnumerable<double> samples)
    {
        AddSamplesProtected(samples);
    }

    // protected abstract method to be implemented by subclasses
    protected abstract void AddSamplesProtected(IEnumerable<double> samples);
}

客户端组装:

using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;

public class ConcreteChannel : Channel
{
    // no need to do anything - public method defined in base class
}

public class ConcreteSensor : Sensor
{
    // domain specific implementation
    public override IObservable<double> WhenNewSamples
    {
        get { return _subject.AsObservable(); }
    }
    Subject<double> _subject = new Subject<double>();

    // template method implemented locally, but called from business logic present in core lib
    protected override void AddSamplesProtected(IEnumerable<double> samples)
    {
        samples.ToList().ForEach(sample => _subject.OnNext(sample));
    }
}

示例程序:

class Program
{
    static void Main(string[] args)
    {
        ConcreteChannel channel = new ConcreteChannel();
        ConcreteSensor sensor = new ConcreteSensor();

        // "plugging" a sensor into a channel
        channel.Sensor = sensor;

        // "sensor" works as a data source for other client code
        sensor.WhenNewSamples.Subscribe(Console.WriteLine);

        // channel works as a data target for data coming from some server class
        channel.AddSamples(Enumerable.Range(0, 10).Select(Convert.ToDouble));
    }
}

输出:

0
1
2
3
4
5
6
7
8
9

【讨论】:

    【解决方案2】:

    您可以使用嵌套类的能力来访问 parent 类的私有/受保护成员:

    abstract class A
    {
        protected abstract void SomeMethod();
    }
    abstract class B { }
    
    class AA : A
    {
        public class BB : B
        {
            public void Test(AA a) => a.SomeMethod(); // no problem to access it here
        }
        protected override void SomeMethod() { } // is not public
    }
    

    【讨论】:

    • 如果我理解正确的话,这会颠倒收容关系。例如,如果我想让 BB 访问 AA.Method,那么 BB 是否需要在 AA 内部?因为目前我的 AA 是 BB 的财产。我有点困惑(虽然我现在要试试)。
    猜你喜欢
    • 2016-06-20
    • 1970-01-01
    • 2014-01-30
    • 1970-01-01
    • 2014-08-20
    • 2019-03-18
    • 2014-09-05
    • 2010-12-12
    相关资源
    最近更新 更多