【问题标题】:Override a static method覆盖静态方法
【发布时间】:2010-01-15 20:09:14
【问题描述】:

我通过继承 RolesService 来扩展一个新类。在 RolesService 中,我有一个静态方法,我想在我的新派生类中覆盖它。当我从派生对象进行调用时,它不使用重写的静态方法,它实际上调用了基类方法。有任何想法吗?

public class RolesService : IRolesService
{
    public static bool IsUserInRole(string username, string rolename)
    {
        return Roles.IsUserInRole(username, rolename);
    }
}

public class MockRoleService : RolesService
{
    public new static bool IsUserInRole(string username, string rolename)
    {
        return true;
    }
}

【问题讨论】:

  • 我想他明白你不能覆盖静态方法。他的问题是“有什么想法吗?”在解决这个问题。不确定人们是否意识到这一点,因为除了 Aaronaught 之外,所有的投票都会给出不包含任何解决这个问题的想法的答案。

标签: c# asp.net asp.net-mvc


【解决方案1】:

您不能覆盖静态方法。静态方法不能是虚拟的,因为它与类的实例无关。

派生类中的“重写”方法实际上是一个新方法,与基类中定义的方法无关(因此有new关键字)。

【讨论】:

    【解决方案2】:

    执行以下操作将使您能够解决静态调用。在你想使用代码的地方通过依赖注入获取一个 IRolesService,然后当你需要 MockRolesService 时,你可以将它传入。

    public interface IRolesService
    {
        bool IsUserInRole(string username, string rolename);
    }
    
    public class RolesService : IRolesService
    {
        public bool IsUserInRole(string username, string rolename)
        {
            return Roles.IsUserInRole(username, rolename);
        }
    }
    
    public class MockRoleService : IRolesService
    {
        public bool IsUserInRole(string username, string rolename)
        {
            return true;
        }
    }
    

    【讨论】:

    • 现在IsUserInRole 不再是静态方法了。
    【解决方案3】:

    您不能覆盖静态方法。

    如果你仔细想想,它并没有真正的意义;为了进行虚拟调度,您需要一个对象的实际实例来检查。

    静态方法也不能实现接口;如果这个类正在实现IRolesService 接口,那么我认为该方法根本不应该是静态的。最好设计一个实例方法,这样您就可以在准备好时将您的MockRoleService 替换为真正的服务。

    【讨论】:

      【解决方案4】:

      您不能覆盖静态方法。您可能会发现 this 很有趣。

      【讨论】:

        【解决方案5】:

        为了调用静态方法,您需要直接引用该类型:

        RolesService.IsUserInRole(...);
        

        在这种情况下,如果您希望能够调用“派生”类的静态方法,删除“new”关键字将允许您:

        MockRoleService.IsUserInRole(...);
        

        并获得预期的函数调用。

        我猜这不是你要找的。您可能在代码中的某处有一些调用,例如前者,并且您希望通过使用 Mocking 工具创建 MockRoleService,您将注入这种新的“类型”来代替旧的。不幸的是,这不是它在静态方面的工作方式。

        模拟工具将创建一个模拟出来的类型的实例,并将其注入来代替调用以构造真实类型。对静态方法的调用会跳过所有这些。

        正如 Aaronaught 所提到的,您可能应该将此方法设为普通的实例方法。这将允许您的模拟服务被正确注入以代替您的常规 RolesService,允许您将方法声明移动到您的 IRolesService 接口中,并在您的 MockRoleService 实现中覆盖它。然后,在您“获取” RolesService 的代码中,您只需调用实例成员而不是静态成员。

        IRolesService svc = MyServiceInjector.GetService<IRolesService>();
        svc.IsUserInRole(...);
        

        【讨论】:

          【解决方案6】:

          这样的事情怎么样:

          public interface IRolesService
          {
              bool IsUserInRoleImpl(string username, string rolename);
          }
          
          public abstract class RolesServiceBase<T>  where T : IRolesService, new()
          {
              protected static T rolesService = new T();
          
              public static bool IsUserInRole(string username, string rolename)
              {
                  return rolesService.IsUserInRoleImpl(username, rolename);
              }
          }
          
          public class RolesService : RolesServiceBase<RolesService>, IRolesService
          {
              public bool IsUserInRoleImpl(string username, string rolename)
              {
                  return Roles.IsUserInRole(username, rolename);
              }
          }
          
          public class MockRoleService : RolesServiceBase<MockRoleService>, IRolesService
          {
              public bool IsUserInRoleImpl(string username, string rolename)
              {
                  return true;
              }
          }
          

          【讨论】:

            【解决方案7】:

            我遇到了类似的问题。我没有使用继承或接口,而只是使用了委托。

                public class RolesService
                {
                    static RolesService()
                    {
                        isUserInRoleFunction = IsUserInRole;
                    }
            
                    public static delegate bool IsUserInRoleFunctionDelegate(string username, string rolename);
            
                    public static IsUserInRoleFunctionDelegate isUserInRoleFunction { get; set; }
            
                    private bool IsUserInRole(string username, string rolename) 
                    {
                        return Roles.IsUserInRole(username, rolename);
                    }
                }
            

            如果您想将方法更改为“newMethod”以进行测试,只需调用

                RolesService.isUserInRoleFunction = newMethod;
            

            【讨论】:

              【解决方案8】:

              静态方法表示与类型本身相关的逻辑。一旦从该类型继承,就不能假定父类型的静态方法适用。您可以执行以下操作:

              public class RolesService : IRolesService
              {
                  public static bool IsUserInRole(string username, string rolename)
                  {
                      return Roles.IsUserInRole(username, rolename);
                  }
              
                  // call this guy within the class
                  protected virtual bool DoIsUserInRole(string username, string rolename) 
                  {
                      return IsUserInRole(username, rolename);
                  }
              }
              
              public class MockRoleService : RolesService
              {
                  public new static bool IsUserInRole(string username, string rolename)
                  {
                      return true;
                  }
              
                  protected override bool DoIsUserInRole(string username, string rolename)
                  {
                      return IsUserInRole(username, rolename); // invokes MockRoleService.IsUserInRole
              
                      // or simply
                      return true;
                  }
              }
              

              【讨论】:

              • 最后一个方法调用IsUserInRole有歧义,需要调用MockRoleService.IsUserInRole
              • @Thomas 不确定您是否在我编辑之前或之后看到了代码,但在当前示例中,对 IsUserInRole 的调用调用了 MockRoleService.IsUserInRole。
              【解决方案9】:

              有两种方法可以让你的模拟对象工作:

              1:将父对象的签名从 RolesService 更改为 IRolesService(假设您尚未使用接口)。然后将模拟实现为 IRolesService 而不是 RolesService。

              public class MockRoleService : IRolesService
              {
                  public new static bool IsUserInRole(string username, string rolename)
                  {
                      return true;
                  }
              }
              
              1. 依赖注入 Roles 对象。

              公共类 MockRoleService : RolesService {

              public MockRoleService ()
              {
                   Roles = OverridenRolesObjectThatAlwaysReturnsTrue;
              }
              

              }

              【讨论】:

                【解决方案10】:

                为什么不使用属性来访问静态值?然后它将支持继承并被覆盖。这似乎是您正在寻找的。​​p>

                public class StaticOverride {
                    public virtual string MyVal { get { return MyStaticMethod(); } }
                
                    public string MyStaticMethod () {
                        return "Example";
                    }
                }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2018-06-21
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-01-04
                  • 2010-10-27
                  相关资源
                  最近更新 更多