简体   繁体   中英

Force property assignment in child classes

I have an abstract immutable base class that defines enforces child classes to be initialized, hence the abstract calls instead of an interface:

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 execution has to be as fast as possible. During initialization stage I have to check initial items and decide what GetItem method should do. It can be one of many implementations based on this set of items.

Since GetItem method has to be as fast as possible it seems much better to have it defined as a property and assign it a straight forward branch-less lambda expression. But using above definition child classes are not forced to set any values to it so implementers may create an invalid child class. Defining an abstract accessor on the property would force them to implement the property which is semantically the same as implementing a method. This doesn't enforce property assignment.

But if I implement it as an overridden abstract method that particular method will need to include all those branches that branch based on items. This means that these branches would get evaluated every time I'd call the method hence making it slow(er).

What I'm actually looking for is a way to force child class implementers to set GetItem property.

How am I supposed to do that?

Also take into consideration that this class will get initialized once and then be used many many times. Used as in calling the GetItem method.

A simplified example class (using property)

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

A simplified example class (using a method)

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

Since GetItem method has to be as fast as possible it seems much better to have it defined as a property and assign it a straight forward branch-less lambda expression

What makes you think it will be faster than a method? The abstract method is the way to go here. It's a more natural approach, and it doesn't have the issue that the property might not be initialized.

But if I implement it as an overridden abstract method that particular method will need to include all those branches that branch based on items. This means that these branches would get evaluated every time I'd call the method hence making it slow(er).

Not sure what you mean by that... what prevents you from putting in the GetItem method the same code you would have put in a Func<TPoint, TItem> in the GetItem property?

As a side note, you should probably think twice about calling a virtual method ( Initialize ) in the constructor, it can lead to unexpected issues: the base constructor is executed before the derived constructor, but it's always the most derived implementation of Initialize that will be called; so if the derived implementation of Initialize relies on things that are initialized in the derived class constructor, it will fail because they won't be initialized yet.

You need to inject somewhat an aspect to your issue. Properties are quite straight forward where you cannot ensure that subclasses has invoked it or not.

You make take advantage of GetItem method making it from abstract to virtual and your base class's implementation will be throwing an exception .

public virtual TItem GetItem(TPoint point)
{
    throw new Exception("Please implement GetItem method");
}

Now, any of the subclasses not overriding this method will fall into exception and ensure subclasses to implement GetItem method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM