c#在基类上执行依赖于继承类初始化的代码

时间:2013-08-01 12:03:23

标签: .net c#-4.0

众所周知,在继承的类构造函数之前总是调用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 个答案:

答案 0 :(得分:1)

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

在这些情况下,通常使用工厂模式来帮助您分离这两种治疗方法。

请阅读this article例如。

祝你好运,可能与你在一起。

答案 1 :(得分: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 as virtual。如果要允许继承类指定该实现,可以通过另一个受保护的属性或方法公开_values

答案 2 :(得分:0)

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

您可以添加属性

private bool loaded;

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

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

加载()应该在加载列表中的值后加载为true,该列表中只包含所有值,例如AllValues。

在您继承的课程中,您可以:

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

然后,只要您想要加载您的值,请调用EnsureLoaded。

答案 3 :(得分: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。我不知道你是否会考虑这个解决方案&#34; Dirty&#34;。