【问题标题】:Can a base class determine if a derived class has overridden a virtual member?基类能否确定派生类是否覆盖了虚拟成员?
【发布时间】:2009-02-06 03:40:03
【问题描述】:

这是我的课程的简化版本:

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();
    }
}

我正在尝试对派生类隐藏锁定代码。但我只想在派生类覆盖 UpdateSharedData 时获得锁;如果没有,我不希望该方法在更新非共享数据之前阻塞并等待所有其他正在更新共享数据的正在运行的实例。

因此,Method 要做的(看似)显而易见的事情是检查并查看 UpdateSharedData 的当前实例的实现是否覆盖了基类的实现。我很确定如果不使用反射,这是不可能的,而且这样做可能是不可取的。

我已经想到了一些解决方法,但它们都很尴尬:

  • 添加派生类的构造函数设置的受保护布尔属性,并检查该属性以查看是否需要锁定。这在向派生类隐藏锁定代码方面做得非常糟糕。
  • 使 UpdateSharedData 方法成为委托属性,设置任何派生类 在其构造函数中将属性分配给私有方法,并且仅在委托不为空时才获得锁。这样更好,但还是有点糟糕。

【问题讨论】:

    标签: c# reflection inheritance overriding


    【解决方案1】:

    如果您定义了一个抽象 Task 和一个 IHasSharedData 接口,那么在 Method 中您检查派生的 Task 是否在执行锁定之前实现 IHasSharedData。只有实现接口的类需要等待。我意识到这避免了回答实际问题,但我认为这将是比使用反射更清洁的解决方案。希望您能找到一个更好的接口名称,与类的实际功能更接近。

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

    【讨论】:

    • 我刚刚意识到 IHasSharedData 看起来很像 LOLCats 代码。 :-) ICanHazSharedData?
    • 这也是我注意到的第一件事!我很难抗拒给它起这样的名字。这正是我一直在寻找的答案。
    【解决方案2】:

    您可以通过一点思考来进行此检查:

    bool IsUpdateSharedDataOverridden()
    {
        Type t = this.GetType();
        MethodInfo m = subType.GetMethod("UpdateSharedData");
    
        return m.DeclaringType == t && m.GetBaseDefinition().DeclaringType == typeof(Task);
    }
    

    【讨论】:

    • 将 m.DeclaringType 直接比较为 t 会更正确。两种不同的类型很可能具有相同的名称。
    • 如果它使用“new”重新声明(而不是覆盖)该方法,那也将报告 true。
    • 仍然不能 100% 工作。方法既可以是虚拟的,也可以是“新的”。
    【解决方案3】:

    其实你说的是两个不同的对象:

    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();
        }
    }
    

    但是,更理想的解决方案是策略模式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-28
      • 2011-06-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多