我有一个抽象的不可变基类,它定义了要初始化的子类,因此抽象调用而不是接口:
public abstract BaseLookup<TPoint, TItem>
{
protected IEnumerable<TItem> items = null;
protected BaseLookup(IEnumerable<TItem> items)
{
this.items = items;
this.Initialize();
}
public abstract void Initialize();
// problem deciding which one
// either implementing a method...
public abstract TItem GetItem(TPoint point);
// ...or assigning a method
public Func<TPoint, TItem> GetItem { get; protected set; }
}
GetItem
执行必须尽可能快。在初始化阶段,我必须检查初始项并确定GetItem
方法应该做什么。它可以是基于这组项目的众多实现之一。
由于GetItem
方法必须尽可能快,所以将它定义为属性并为其分配一个直接的无分支lambda表达式似乎要好得多。但是使用上面定义的子类不会强制为它设置任何值,因此实现者可能会创建一个无效的子类。在属性上定义abstract
访问器将强制它们实现与实现方法在语义上相同的属性。这不会强制执行属性分配。
但是如果我将它实现为一个重写的抽象方法,那么特定方法需要包含所有那些基于项目分支的分支。这意味着每次调用方法时都会对这些分支进行评估,从而使其变慢(呃)。
我真正想要的是强制子类实现者设置GetItem
属性的方法。
我该怎么做?
还要考虑到这个类会被初始化一次然后被多次使用。用于调用GetItem
方法。
public class IteratorLookup<TPoint, TItem> : BaseLookup<TPoint, TItem>
{
private TItem single = null;
public IteratorLookup(IEnumerable<TItem> items) : base(items);
public override void Initialize()
{
if (this.items != null && this.items.Count > 0)
{
if (this.items.Count > 1)
{
this.GetItem = point => this.items[this.GetIndex(point)];
}
else
{
this.GetItem = irrelevant => this.single;
}
}
else
{
this.GetItem = irrelevant => null;
}
}
private int GetIndex(TPoint point) { ... }
}
public class IteratorLookup<TPoint, TItem> : BaseLookup<TPoint, TItem>
{
private TItem single = null;
public IteratorLookup(IEnumerable<TItem> items) : base(items);
public override void Initialize()
{
// implementing minor speed up
if (this.items != null && this.items.Count == 1)
{
this.single = items[0];
}
}
public override TItem GetItem(TPoint point)
{
if (this.items != null && this.items.Count > 0)
{
if (this.items.Count > 1)
{
return this.items[this.GetIndex(point)];
}
return this.single;
}
return null;
}
private int GetIndex(TPoint point) { ... }
}
答案 0 :(得分:0)
由于GetItem方法必须尽可能快,因此将它定义为属性并为其分配一个直接的无分支lambda表达式似乎要好得多
是什么让你觉得它比方法更快?这是抽象方法。这是一种更自然的方法,它没有可能无法初始化属性的问题。
但是如果我将它实现为一个重写的抽象方法,那么特定方法需要包含所有那些基于项目分支的分支。这意味着每次调用方法时都会对这些分支进行评估,从而使其变慢(呃)。
不确定你的意思是什么......是什么阻止你在GetItem
方法中放入与Func<TPoint, TItem>
属性中的GetItem
相同的代码?< / p>
作为旁注,您可能应该三思而后行,在构造函数中调用虚方法(Initialize
),这可能会导致意外问题:基础构造函数在派生构造函数之前执行,但它始终是将被调用的Initialize
的大多数派生实现;因此,如果Initialize
的派生实现依赖于派生类构造函数中初始化的内容,则它将失败,因为它们尚未初始化。
答案 1 :(得分:-1)
您需要为您的问题注入一些方面。属性非常简单,您无法确保子类是否已调用它。
您利用GetItem
方法将其从abstract
发送到virtual
,您的基类实现将抛出exception
。
public virtual TItem GetItem(TPoint point)
{
throw new Exception("Please implement GetItem method");
}
现在,任何未覆盖此方法的子类都将属于异常,并确保子类实现GetItem
方法。