Переопределить статический метод - PullRequest
39 голосов
/ 15 января 2010

Я расширяю новый класс путем наследования от 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;
    }
}

Ответы [ 10 ]

40 голосов
/ 15 января 2010

Вы не можете переопределить статический метод. Статический метод не может быть виртуальным, поскольку он не связан с экземпляром класса.

Метод переопределения в производном классе на самом деле является новым методом, не связанным с тем, который определен в базовом классе (следовательно, ключевое слово new).

19 голосов
/ 16 января 2010

Выполнение следующих действий позволит вам обойти статический вызов.Если вы хотите использовать код, возьмите IRolesService посредством внедрения зависимости, тогда, когда вам нужен MockRolesService, вы можете передать это.

18 голосов
/ 15 января 2010

Вы не можете переопределить статический метод.

Если вы думаете об этом, это на самом деле не имеет смысла; для виртуальной отправки вам необходим фактический экземпляр объекта для проверки.

Статический метод также не может реализовать интерфейс; если этот класс реализует интерфейс IRolesService, то я бы сказал, что метод не должен быть статическим вообще. Лучше разработать метод экземпляра, чтобы вы могли заменить MockRoleService на реальный сервис, когда будете готовы.

12 голосов
/ 15 января 2010

Вы не можете переопределить статический метод. Вы можете найти это интересное чтение.

3 голосов
/ 16 января 2010

Что-то вроде этого:

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;
    }
}
3 голосов
/ 16 января 2010

Чтобы вызвать статический метод, вам понадобится прямая ссылка типа:

RolesService.IsUserInRole(...);

В этом случае, если вы хотите иметь возможность и вызывать статический метод «производного» класса, удаление ключевого слова «new» позволит вам:

MockRoleService.IsUserInRole(...);

и получите ожидаемый вызов функции.

Я предполагаю, что это не то, что вы ищете. Скорее всего, в вашем коде есть какой-то вызов, похожий на предыдущий, и вы надеетесь, что с помощью инструмента Mocking для создания MockRoleService вы внедрите этот новый «тип» вместо старого. К сожалению, это не так со статикой.

Инструмент mocking создаст экземпляр типа mocked out и внедрит его вместо вызова для создания реального типа. Вызов статического метода пропускает все это.

Как уже упоминал Аарона, вы, вероятно, должны сделать этот метод обычным методом экземпляра. Это позволит правильно внедрить ваш фиктивный сервис вместо вашего обычного RolesService, позволит вам переместить объявление метода в интерфейс IRolesService и переопределить его в вашей реализации MockRoleService. Затем в коде, где вы «получаете» RolesService, вы просто вызываете член экземпляра вместо статического.

IRolesService svc = MyServiceInjector.GetService<IRolesService>();
svc.IsUserInRole(...);
2 голосов
/ 26 июля 2014

У меня была похожая проблема. Я не использовал наследование или интерфейс, а просто использовал делегат.

    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;
0 голосов
/ 08 сентября 2015

Почему бы не использовать свойство для доступа к статическому значению?Тогда это поддержит наследование и будет переопределено.Что, кажется, то, что вы ищете.

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

    public string MyStaticMethod () {
        return "Example";
    }
}
0 голосов
/ 16 января 2010

Есть два способа заставить ваш фиктивный объект работать:

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

}

0 голосов
/ 15 января 2010

Статический метод представляет логику, относящуюся к самому типу. Как только вы наследуете от этого типа, нельзя предполагать, что статические методы родительского типа применяются. Что вы можете сделать, это следующее:

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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...