Как сделать это сложное понижение с общими ограничениями? - PullRequest
0 голосов
/ 02 октября 2018

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

У меня есть класс DefaultController:

public abstract partial class DefaultController<T> : Controller where T : IBaseEntity
{

}

IBaseEntity is:

public interface IBaseEntity
{
    int Id { get; set; }
    DateTime CreatedOn { get; set; }
    DateTime ModifiedOn { get; set; }
    int CreatedBy { get; set; }
    int ModifiedBy { get; set; }
    int OwnerId { get; set; }

}

У меня есть экземпляр контроллера, который наследует DefaultController:

public class WorkflowController : DefaultController<Workflow>
{
}

Workflow наследует BaseEntity, который реализует IBaseEntity.

Теперь, внутри моего фильтра действий, с точки зрения кода, невозможно узнать, на каком контроллере выполняется запрос, поэтому я пытаюсь понизить его до DefaultController

public class AddHeaders : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {

        var defaultControllerGenericType = controller.GetType().BaseType.GenericTypeArguments.FirstOrDefault();
        //this retrieve with which type DefaultController was initiated with...
        var controller = filterContext.Controller as DefaultController<BaseEntity>; 
        //this returns null...
        var controller2 = filterContext.Controller as DefaultController<IBaseEntity>;
        //this does so as well.

    }
}

Iя пытался использовать defaultControllerGenericType, но я нигде не могу передать его, или, по крайней мере, мне не хватает правильного синтаксиса.

Есть ли способ сделать это?

Ответы [ 2 ]

0 голосов
/ 02 октября 2018

Поучительно понять, почему это невозможно.

public abstract partial class DefaultController<T> : Controller where T : IBaseEntity { ... }
public class WorkflowController : DefaultController<Workflow> { ... }

Здесь, позвольте мне переписать это:

class Container { }
class Animal { }
class Fish : Animal { }
class Cage<T> : Container where T : Animal 
{ 
  public T Contents { get; set; }
}
class Aquarium : Cage<Fish> { }

Теперь вопрос в том, что происходит, когда у меня есть:

Aquarium a = new Aquarium(); // Fine
Cage<Fish> cf = a; // Fine
Container c = a; // Fine
Cage<Animal> ca1 = a; // Nope
Cage<Animal> ca2 = a as Cage<Animal>; // Null!

Почему это запрещено?Ну, предположим, что это разрешено.

Cage<Animal> ca = a; // Suppose this is legal
Tiger t = new Tiger(); // Another kind of animal.
ca.Contents = t; // Cage<Animal>.Contents is of type Animal, so this is legal

И мы просто поместили тигра в аквариум.Вот почему это незаконно.

Как говорит Джон Скит, ваза с яблоками - это не ваза с фруктами.Вы можете положить банан в вазу с фруктами, но вы не можете положить банан в вазу с яблоками, и поэтому они бывают разных видов!

0 голосов
/ 02 октября 2018

Вы не можете сделать это с классом (т. Е. DefaultController), но если вы хотите извлечь нужные детали в интерфейс , то это можно сделать вариантом,Вот ковариантный пример:

public interface IEntityController<out T> where T : IBaseEntity
{

}

public abstract partial class DefaultController<T>: Controller, IEntityController<T> 
    where T : IBaseEntity
{

}

Используйте его следующим образом:

    var controller = filterContext.Controller as IEntityController<IBaseEntity>; 

Однако учтите, что вам придется решать, является ли ваш интерфейс ковариантным или контравариантным.есть методы, которые принимают значения IBaseEntity в качестве параметров, или у вас есть только методы, которые их возвращают?Если вы делаете и то, и другое, тогда просто небезопасно предполагать, что вы можете вызывать эти методы для подклассов вашего контроллера по умолчанию.

Если, с другой стороны, вам даже не нужен универсальный параметр влюбой из ваших сигнатур методов, вы можете упростить вещи и сделать ваш интерфейс не универсальным:

public interface IEntityController
{

}

public abstract partial class DefaultController<T>: Controller, IEntityController
    where T : IBaseEntity
{

}

...

    var controller = filterContext.Controller as IEntityController; 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...