【问题标题】:Force override method if another method is overriden强制覆盖另一个方法的方法
【发布时间】:2015-03-13 09:14:03
【问题描述】:

如果另一个方法被覆盖,有没有办法强制覆盖一个虚拟方法?

public class BaseClass
{
    protected virtual void A()
    { 
        // a default action called first
    }

    protected virtual void B()
    { 
        // a default action called second that,
        // if A was overriden, makes no sense
    }
}

编辑

非常感谢您的回答。看看如何实现这一点非常有趣,但对于我的明确案例来说,这并不是至关重要的。

另外,我忘了提到这些方法将如何使用:(在 BaseClass 中)

pulbic bool EditEntity(Guid id)
{
    A();

    // Some code that edits Entites

    B();
}

【问题讨论】:

  • 如果Equals 被覆盖,没有人会强迫你覆盖GetHashCode
  • 问题是如果A 被覆盖,为什么B 不再有意义。
  • 如果你覆盖其中一个,不覆盖另一个是一个糟糕的设计,它可能会产生一个警告(至少在某些静态分析工具中),但它并没有被语言禁止跨度>
  • @TimSchmelter 我正在编辑与实体框架的关系,默认设置是什么都不做。否则将调用不必要的检查。这只是一个优化的事情,没有什么过分重要的。
  • 使其抽象化并且不实现方法体?然后派生类必须实现它们

标签: c#


【解决方案1】:

不,你不能。但这让我想到你怎么能实现同样的概念?

我想出的最佳想法是声明一个接口,该接口具有要覆盖的方法包。

 public interface IMyOverridablePackage
 {
     void A_Override();
     void B_Override();
 }

然后给基类一个受保护的方法,子类可以显式地覆盖这组方法。

protected void SetOverride(IMyOverridablePackage overridablePackage)
{
    _overridablePackage = overridablePackage;
}

那么这里有两个类,一个会覆盖方法集,一个不会覆盖方法集:

 public class NotOverriding : MyBaseClass
 {
 }


public sealed class Overriding : MyBaseClass, IMyOverridablePackage
{
    public Overriding()
    {
        SetOverride(this);
    }

    void IMyOverridablePackage.A_Override()
    {
         Console.WriteLine("Overriding.A_Override");            
    }

    void IMyOverridablePackage.B_Override()
    {
        Console.WriteLine("Overriding.B_Override");
    }
}

以及基类的实现:

 public abstract class MyBaseClass 
 {

     private IMyOverridablePackage _overridablePackage;

     public void A()
     {
         _overridablePackage.A_Override();
     }

     public void B()
     {
         _overridablePackage.B_Override();
     }


     private class MyDefaultPackage : IMyOverridablePackage
     {
         private readonly MyBaseClass _myBaseClass;

         internal MyDefaultPackage(MyBaseClass myBaseClass) 
         {
             _myBaseClass = myBaseClass;
         }

         void IMyOverridablePackage.A_Override() 
         {
             _myBaseClass.A_Impl();
         }

         void IMyOverridablePackage.B_Override()
         {
             _myBaseClass.B_Impl();
         }
     }

     protected MyBaseClass()
     {
         _overridablePackage = new MyDefaultPackage(this);
     }

     private void A_Impl()
     {
         Console.WriteLine("MyBaseClass.A_Impl");
     }

     private void B_Impl()
     {
         Console.WriteLine("MyBaseClass.B_Impl");
     }

     protected void SetOverride(IMyOverridablePackage overridablePackage)
     {
         _overridablePackage = overridablePackage;
     }
 }

这确实实现了目标,但当然你必须问“我想要多少?”额外的代码值得吗?

这是一个有效的 dotnetfiddle:https://dotnetfiddle.net/xmPn20

【讨论】:

    【解决方案2】:

    也许你不能通过编译器错误来强制它,但你可以编写一个测试,通过一些属性断言这些方法是同步的。也可以看出存在一些依赖关系。

    一个粗略的例子是这样的:

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    public class VersionAttribute : Attribute
    {
        public VersionAttribute(string version)
        {
            Version = version;
        }
    
        public string Version { get; set; }
    }
    
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    public class DependentAttribute : Attribute
    {
        public string DependentOnMethod { get; set; }
        public string DependentOnVersion { get; set; }
    }
    
    
    [Dependent(DependentOnMethod = "OtherMethod", DependentOnVersion = "1")]
    public static void FirstMethod()
    {
    }
    
    [Version("1")]
    public static void OtherMethod()
    {
    }
    

    以及断言版本号的测试:

    [Test]
    public void TestVersions()
    {
        foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
        {
            foreach (var method in type.GetMethods())
            {
                foreach (var customAttribute in method.GetCustomAttributes())
                {
                    var dependent = customAttribute as DependentAttribute;
                    if (dependent != null)
                    {
                        var methodInfo = type.GetMethod(dependent.DependentOnMethod);
                        Assert.That(methodInfo, Is.Not.Null, "Dependent method not found");
                        VersionAttribute version = methodInfo.GetCustomAttributes().OfType<VersionAttribute>().FirstOrDefault();
                        Assert.That(version, Is.Not.Null, "No version attribute on dependent method");
                        Assert.That(dependent.DependentOnVersion, Is.EqualTo(version.Version));
                    }
                }
            }
        }
    }
    

    因此,如果您更新其中一种方法,则需要更新Version 属性或Dependent 属性的版本号。希望总比没有好。

    【讨论】:

      【解决方案3】:

      你可以改变你的设计:

      public abstract class BaseClass
      {
          protected abstract void A();
      }
      
      public class BaseClassEx
      {
          protected sealed override void A()
          { 
              // action Calling B
          }
      
          protected virtual void B()
          { 
              // a default action called second
          }
      }
      

      【讨论】:

        【解决方案4】:

        Equals(实际上是 Equals 重载、具体类型和对象)和 GetHashCode 的情况下,Resharper 包含一个规则,当您忘记实现其中之一时,Resharper 会在其 IntelliSense 中显示警告。

        您可以在代码中通过基类的构造函数中的运行时检查来强制执行它:

        public class Base
        {
          public Base()
          {
            var baseA = typeof (Base).GetRuntimeMethod("MethodA", new Type[0]);
            var baseB = typeof (Base).GetRuntimeMethod("MethodB", new Type[0]);
            var derivedA = GetType().GetRuntimeMethod("MethodA", new Type[0]);
            var derivedB = GetType().GetRuntimeMethod("MethodB", new Type[0]);
        
            if (baseA.DeclaringType == derivedA.DeclaringType ^ 
                baseB.DeclaringType == derivedB.DeclaringType)
              throw new InvalidOperationException("You must override MethodA and MethodB together.");
          }
        
          public virtual string MethodA() { return "Hello"; }
          public virtual int MethodB() { return 123; }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-05-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-07
          • 1970-01-01
          • 2016-11-16
          相关资源
          最近更新 更多