开发者

Override a static method

I am extending a new class by inheriting from RolesService. In RolesService I have a static methog that I would like to override in my newly derived class. When I make the call from my derived object it does not use the overridden static method it actually calls the base class method. Any ideas?

public class RolesService : IRolesService
{
    public static bool IsUserInRole(string username, string rolename)
    {
开发者_如何学JAVA        return Roles.IsUserInRole(username, rolename);
    }
}

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


You can't override a static method. A static method can't be virtual, since it's not related to an instance of the class.

The "overriden" method in the derived class is actually a new method, unrelated to the one defined in the base class (hence the new keyword).


Doing the following the will allow you to work around the static call. Where you want to use the code take an IRolesService via dependency injection then when you need MockRolesService you can pass that in.

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


You cannot override a static method.

If you think about it, it doesn't really make sense; in order to have virtual dispatch you need an actual instance of an object to check against.

A static method also can't implement an interface; if this class is implementing an IRolesService interface then I would contend that the method should not be static at all. It's better design to have an instance method, so you can swap out your MockRoleService with a real service when you're ready.


You can't override a static method. You might find this an interesting read.


In order to call a static method, you'll need a direct reference of the type:

RolesService.IsUserInRole(...);

In which case, if you want to be able and call the "derived" class's static method, dropping the "new" keyword will allow you to:

MockRoleService.IsUserInRole(...);

and get the expected function call.

My guess is that this isn't what you're looking for. You likely have some call somewhere in your code like the former, and you're hoping that by using a Mocking tool to create a MockRoleService, you'd be injecting this new "type" in place of the old one. Unfortunately, that's not how it works with statics.

A mocking tool will create an instance of the mocked out type and will inject that in place of a call to construct the real type. A call to a static method skips all of that.

As Aaronaught mentioned, you should probably make this method a normal instance method. This would allow your mock service to be properly injected in place of your regular RolesService, allow you to move the method declaration into your IRolesService interface, and override it in your MockRoleService implementation. Then, in the code where you "get" a RolesService, you just call the instance member instead of the static.

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


What about something like this:

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


I had a similar problem. I didn't use inheritance or an interface, but simply used a delegate.

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

If you want to change the method to "newMethod" for testing purposes, just call

    RolesService.isUserInRoleFunction = newMethod;


A static method represents logic pertinent to the type itself. Once you inherit from that type, the static methods of the parent type cannot be assumed to apply. What you can do is the following:

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


There are two ways you might make your mock object work:

1: Change the signature of your parent object from RolesService to IRolesService (assuming you aren't using the Interface already) . Then implement the mock to IRolesService instead of RolesService.

public class MockRoleService : IRolesService
{
    public new static bool IsUserInRole(string username, string rolename)
    {
        return true;
    }
}
  1. Dependency inject the Roles object.

public class MockRoleService : RolesService {

public MockRoleService ()
{
     Roles = OverridenRolesObjectThatAlwaysReturnsTrue;
}

}


Why not use a property to access the static value? Then it would support inheritance and be overridable. Which seems to be what you're looking for.

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

    public string MyStaticMethod () {
        return "Example";
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜