【问题标题】:Passing a member-access function in the constructor在构造函数中传递成员访问函数
【发布时间】:2021-11-17 14:38:02
【问题描述】:

假设我有一个类似的帮助类

public class Selection<T, W> : ISelection<T,W> where W : ICollection<T>
{
    public Selection(Func<W> selectableItemsProvider)
    {
        ...
    }
}

由于 C# 不支持委托接口实现,我想我会为自己节省一些样板文件,只需扩展 Selection 类...

public class MyFoo : Selection<Blah, List<Blah>>
{
    private List<Blah> _blahs = new List<Blah>();


    public MyFoo() : base(() => _blahs)
    {
        ...
    }
}

除非我不能那样做,我可以吗,因为

无法在静态上下文中访问非静态属性“_blahs”

即使已经知道在对象构造之后才会调用提供程序。

有没有办法解决这个问题,还是我坚持添加样板代码?

【问题讨论】:

  • 添加受保护的空构造函数然后允许直接分配selectableItemsProvider(例如使其成为受保护的成员)?
  • 你的意思是不会在Selection构造函数中调用提供者?
  • @Sweeper 完全正确。
  • 我会按照@Evk 的建议去做:protected Func&lt;W&gt; SelectableItemsProvider { get; }protected Selection() { }public MyFoo() { SelectableItemsProvider = () =&gt; _blahs; }
  • @Evk 但是我不能再要求在对象实例化之后设置提供程序。

标签: c# constructor delegates member


【解决方案1】:

一个有点迂回的方法是将每次返回相同列表的 lambda 传递给基类构造函数。然后调用那个 lambda 来初始化 blahs:

public class Selection<T, W>: ISelection<T, W> where W : ICollection<T> {

    // assuming you have a property like this that is initialised by the constructor...
    protected Func<W> SelectableItemsProvider { get; }
    public Selection(Func<W> selectableItemsProvider)
    {
        SelectableItemsProvider = selectableItemsProvider;
    }
}

public class MyFoo : Selection<Blah, List<Blah>>
{
    private List<Blah> _blahs;


    public MyFoo() : base(new List<Blah>().CaptureInFunc())
    {
        _blahs = SelectableItemsProvider();
    }
}

CaptureInFunc 是一个扩展方法,声明如下:

public static Func<T> CaptureInFunc<T>(this T t) => () => t;

这为我们提供了一个 lambda,它每次都返回 t

【讨论】:

    【解决方案2】:

    一种方法可能是首先引入基本抽象类。这个类将包含所有逻辑:

    public abstract class SelectionBase<T, W> where W : ICollection<T>
    {
        protected SelectionBase() {
    
        }
    
        protected abstract Func<W> GetSelectableItemsProvider();
    }
    

    然后更改您当前的Selection 以继承它并在构造函数中接受选择器,这就是整个实现:

    public sealed class Selection<T, W> : SelectionBase<T, W> where W: ICollection<T> {
        private readonly Func<W> _selectableItemsProvider;
    
        public Selection(Func<W> selectableItemsProvider) {
            _selectableItemsProvider = selectableItemsProvider;
        }
    
        protected override Func<W> GetSelectableItemsProvider() {
            return _selectableItemsProvider;
        }
    }
    

    现在,如果您想以问题中提到的方式扩展选择:

    public class SpecificSelection : SelectionBase<string, List<string>> {
        private List<string> _blah;
    
        public SpecificSelection() {
    
        }
    
        protected override Func<List<string>> GetSelectableItemsProvider() {
            return () => _blah;
        }
    }
    

    【讨论】:

      【解决方案3】:

      您不能在调用基本构造函数时引用“this”的成员,因为“this”还不存在。

      我建议组合而不是继承。该类仍然可以实现与帮助程序相同的接口,然后将所有调用委托给真正的实现。

      public class MyFoo : ISelection<Blah, List<Blah>>
      {
          private List<Blah> _blahs;
          
          private ISelection<Blah, List<Blah>> _implementation;
      
          public MyFoo()
          {
              _blahs = new List<Blah>();
              _implementation = new Selection<Blah, List<Blah>>(() => _blahs);
          }
          
          public void DoSomethingWithSelection()
          {
              _implementation.DoSomethingWithSelection();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2012-08-21
        • 2020-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多