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