Подтвердить что ты не робот

Переопределить статический метод

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

Ответ 1

Выполнение следующих действий позволит вам обойти статический вызов. Если вы хотите использовать код, используйте 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;
    }
}

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

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

RolesService.IsUserInRole(...);

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

MockRoleService.IsUserInRole(...);

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

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

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

Как упоминалось 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;
    }
}

Ответ 9

Есть два способа, которыми вы могли бы сделать свой макетный объект:

1: измените подпись родительского объекта с RolesService на IRolesService (если вы уже не используете интерфейс). Затем реализуйте макет в IRolesService вместо RolesService.

public class MockRoleService : IRolesService
{
    public new static bool IsUserInRole(string username, string rolename)
    {
        return true;
    }
}
  1. Зависимость вводит объект Роли.

открытый класс MockRoleService: RolesService {

public MockRoleService ()
{
     Roles = OverridenRolesObjectThatAlwaysReturnsTrue;
}

}

Ответ 10

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

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

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