3

众所周知,在 C# 中,基类构造函数总是在继承类构造函数之前调用。因此,我面临一个问题,我找不到解决方法:

有一个基类

public class BaseClass 
{
  public IValuesProvider ValuesProvider {get; protected set; }
  public virtual IList<Value> Values 
  {
      get {return ValuesProvider.GetAll(); }
  }
  public BaseClass(IValuesProvider valuesProvider)
  {
       ValuesProvider = valuesProvider;
       Load();
  }

  public virtual void Load()
  {
     foreach (var value in Values)
     {
       // DO something with value
     }
  } 

}

和一个继承的类

public class InheritedClass : BaseClass
{

  public int? Filter {get; protected set;}

  public override IList<Value> Values 
  {
      get {return base.Values.Where(v => v.Id > Filter); }
  }

  public InheritedClass (IValuesProvider valuesProvider, int filter)
     : base (valuesProvider)
  {
      Filter = filter;
  }     
}

如果我实例化 InheritedClass,我将在尝试返回值时在 Filter 上获得 Null 引用异常。所以我需要在分配“过滤器”时执行 Load() 并且只执行一次。我在我的约束中添加了 InheritedClass 也可以被继承,例如:

 public class InheritedClass2 : InheritedClass
{

  public int? Filter2 {get; protected set;}

  public override IList<Value> Values 
  {
      get {return base.Values.Where(v => v.Id > Filter2); }
  }

  public InheritedClass2 (IValuesProvider valuesProvider, int filter1, int filter 2)
     : base (valuesProvider, filter1)
  {
      Filter2 = filter2;
  }     
}

如何在不编写脏代码的情况下有效地调用 Load ?

4

4 回答 4

1

简而言之,您要做的是有一个构造函数来设置成员变量并进行初始化工作,并且您要确保这两种处理的顺序。

在这些情况下,通常使用工厂模式来帮助您区分这两种处理方式。

例如阅读这篇文章

祝你好运,愿锋利与你同在。

于 2013-08-01T13:10:29.533 回答
1

您肯定必须将负载移出构造函数。下面的解决方案可以解决问题,但需要您在基类中保留一个私有值列表。

public class BaseClass 
{
    public IValuesProvider ValuesProvider { get; protected set; }
    private bool isLoaded = false;
    private List<Value> _values;
    public virtual IList<Value> Values 
    {
        get 
        {
            if (!isLoaded)
            {
                _values = ValuesProvider.GetAll();
                Load();
                isLoaded = true;
            }
            return _values; 
        }
    }
    public BaseClass(IValuesProvider valuesProvider)
    {
        ValuesProvider = valuesProvider;
    }

    public virtual void Load()
    {
        foreach (var value in _values)
        {
            // DO something with value
        }
    }
}

我不确定您为什么将 Load 作为虚拟。如果您希望允许继承类指定该实现,您可以_values通过另一个受保护的属性或方法公开。

于 2013-08-01T13:12:20.490 回答
0

我认为延迟加载是这里的方法。

您可以添加属性

private bool loaded;

到您的基类并添加一个方法

protected void EnsureLoaded() {
  if (!loaded) Load();
}

加载列表中的值后,Load() 应该设置加载为真,该列表仅包含所有值,例如 AllValues。

在您继承的类中,您可以:

public override IList<Value> Values 
  {
      get {
        EnsureLoaded();
        return base.AllValues.Where(v => v.Id > Filter); 
      }
  } 

然后,每当您希望加载您的值时,请调用 EnsureLoaded。

于 2013-08-01T12:13:42.783 回答
0

我有一个类似的问题,我的解决方案是

public class BaseClass
{
    private c_Text;

    public List<int> c_Series;

    public BaseClass(string _Text)
    {
        c_Text = _Text;

        Init();
    }

    protected virtual void Init()
    {           
        Initialize_Series();
    }

    protected virtual void Initialize_Series()
    {
        c_Series = Globals.Default_Series;
    }
}

public class InheritedClass1 : BaseClass
{
    protected c_Series1;

    private Loaded = false;

    public InheritedClass1(string _Text, List<int> _Input_Series1) : base(_Text)
    {
        c_Series1 = _Input_Series1;

        Loaded = true;

        Init();
    }

    protected override Init()
    {
        if(Loaded)
            base.Init();
    }

    protected override void Initialize_Series()
    {
        c_Series = new List<int>(c_Series1);
    }
}

public class InheritedClass2 : InheritedClass1
{
    protected c_Series2;

    private Loaded = false;

    public InheritedClass1(string _Text, List<int> _Input_Series1, List<int> _Input_Series2) : base(_Text, _Input_Series1)
    {
        c_Series2 = _Input_Series2;

        Loaded = true;

        Init();
    }

    protected override Init()
    {
        if(Loaded)
            base.Init();
    }

    protected override void Initialize_Series()
    {
        c_Series = new List<int>();
        int l_Result = 0;

        foreach(int l_List1_Int in c_Series1)
        {
            l_Result = l_List1_Int;
            foreach(int l_List2_Int in c_Series2)
            {
                l_Result = l_Result + l_List2_Int;
                c_Series.Add(l_Result);
            }
        }
    }
}

这确保了 Init 在所有构造函数正确初始化成员之后执行一次,即使您继续继承类也是如此。我不知道你是否会考虑这个解决方案“脏”。

于 2015-04-27T15:09:49.127 回答