强制子类中的属性赋值

时间:2011-11-15 10:08:16

标签: c# properties abstract-class

我有一个抽象的不可变基类,它定义了要初始化的子类,因此抽象调用而不是接口:

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) { ... }
}

2 个答案:

答案 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方法。