Can a base class determine if a derived class has

2019-04-08 03:54发布

Here's a simplified version of my class:

public abstract class Task
{
    private static object LockObject = new object();

    protected virtual void UpdateSharedData() { }
    protected virtual void UpdateNonSharedData() { }

    public void Method()
    {
       lock(LockObject)
       {
          UpdateSharedData();
       }
       UpdateNonSharedData();
    }
}

I'm trying to hide the locking code from derived classes. But I only want to obtain the lock if the derived class overrides UpdateSharedData; if it doesn't, I don't want the method to block and wait on all of the other running instances that do update shared data before it updates the non-shared data.

So the (seemingly) obvious thing for Method to do is to check and see if the current instance's implementation of UpdateSharedData has overriden the base class's implementation. I'm pretty sure this isn't possible without using reflection, and it's probably not desirable to do that.

I've thought of some workarounds to this, but they're all pretty awkward:

  • Add a protected bool property that the derived class's constructor sets, and check that property to see if a lock is needed. That's doing a pretty terrible job of hiding the locking code from the derived classes.
  • Make the UpdateSharedData method a delegate property, have any derived class set the property to a private method in its constructor, and only obtain the lock if the delegate isn't null. That's better, but it still kind of sucks.

3条回答
Ridiculous、
2楼-- · 2019-04-08 04:25

What if you defined an abstract Task and a IHasSharedData interface, then in Method you check if the derived Task implements IHasSharedData before doing the lock. Only classes that implement the interface need wait. I realize that this avoids answering the actual question, but I think it would be a cleaner solution than using reflection. Hopefully, you'd find a better name for the interface that more closely matches what the classes actually do.

public interface IHasSharedData
{
    void UpdateSharedData();
}

public abstract class Task
{
    private static object LockObject = new object();

    protected virtual void UpdateNonSharedData() { }

    public void Method()
    {
         if (this is IHasSharedData)
         {
            lock(LockObject)
            {
                UpdateSharedData();
            }
         }
         UpdateNonSharedData();
    }
}

public class SharedDataTask : Task, IHasSharedData
{
    public void UpdateSharedData()
    {
       ...
    }
}
查看更多
三岁会撩人
3楼-- · 2019-04-08 04:25

You can do this check with a smidge of reflection:

bool IsUpdateSharedDataOverridden()
{
    Type t = this.GetType();
    MethodInfo m = subType.GetMethod("UpdateSharedData");

    return m.DeclaringType == t && m.GetBaseDefinition().DeclaringType == typeof(Task);
}
查看更多
迷人小祖宗
4楼-- · 2019-04-08 04:27

Actually, you are talking about two different objects:

public abstract class Task {    
    protected virtual void UpdateNonSharedData() { }

    public virtual void Method()    
    {   
        UpdateNonSharedData();    
    }
}

public abstract class TaskWithSharedData : Task {    
    private static object LockObject = new object();    

    protected virtual void UpdateSharedData() { }

    public overrides void Method()    
    {       
        lock(LockObject)
        {          
            UpdateSharedData();       
        }   
        base.Method();
    }
}

But, more ideal solution will be the Strategy Pattern.

查看更多
登录 后发表回答