【发布时间】:2011-11-15 10:08:16
【问题描述】:
我有一个抽象的不可变基类,它定义了强制初始化子类,因此抽象调用而不是接口:
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) { ... }
}
【问题讨论】:
-
(1) 通常应该避免在构造函数中调用抽象成员。 (2) 有没有实测过分支版和非分支版的时间差?我假设调用委托比执行分支慢。 --> 对我来说这听起来像是过早的优化。
-
除了我刚才的评论,我真的不明白你想做什么:-) 有人用某个
TPoint实例调用GetItem。现在您要执行某个功能。对GetItem的每次调用都具有相同的功能吗?并且这个功能是在Initialize中根据传入构造函数的项目来选择的? -
@DanielHilgarth:应该避免调用抽象成员是的,但无论如何它们都会有一个实现,因为否则代码将无法编译。根据您的 cmets,我通过提供更多代码来编辑我的问题以了解我的意思...
-
我不知道您为什么认为调用
abstract方法与调用virtual方法有什么不同。调用virtual方法(以及就此而言abstract方法)的问题是派生类的构造函数尚未执行,因此您正在处理未完全实例化的对象!有关更多信息,请参阅here。 -
顺便说一句:你没有回答我关于性能比较的问题。你有没有把你发布的代码和方法中直接包含分支的版本进行比较?
标签: c# properties abstract-class