【问题标题】:casting to an abstract generic base class转换为抽象泛型基类
【发布时间】:2014-02-19 04:07:10
【问题描述】:

我有一个从 Mvc Controller 继承的抽象泛型类,它使用泛型类型来创建项目字典,类似于:

public abstract class BaseController<TElement> : Controller where TElement : BaseElement
{
    public Dictionary<string, TElement> Stuff { get; set; }
    string Name;

    public BaseController()
    {
        this.Name = Helper.GetName();
        this.Stuff = Helper.GetStuff(Name) as Dictionary<string, TElement>;
    }
}

然后我有几个不同的 BaseController 实现,它们根据命名对象的标准传入不同类型的 BaseElement(我相信这部分无关紧要,但如果它影响我的最终结果,请告诉我)。

问题是稍后我需要检查动作过滤器中的“Stuff”属性是否为空,该动作过滤器通过基本 Mvc Controller 属性访问 BaseController 的实例。

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    var controller = filterContext.Controller as **BaseWidgetController**; // <-- here
    if (controller == null)
        throw new Exception(filterContext.Controller.GetType().ToString());
}

我的“BaseController”是一个控制器,因此它确实适合该属性,但我不知道如何将其转换为我的 BaseController 类型以获取 Stuff 属性...

这可以吗?我在搜索提到协方差时看到过,但我似乎无法理解它,这是我完成这项工作所需要的吗?

我也看到使用反射作为一种解决方案,但这很昂贵,并且不适用于我的特定情况。

最后我发现如果我将基定义为接口而不是抽象类,这可能会起作用,但我需要该基行为,因为它将在所有继承的类型之间共享...

我输入这个问题的主要原因是因为 SO 总是会提出非常相似的问题,而我通常最终会找到我的答案,但这次我真的迷失了协方差和泛型,所以我可以使用一些洞察力来判断这是否可能,或者我是否应该以完全不同的方式这样做......

【问题讨论】:

  • 也许我有一个缓慢的时刻。如果Thing 继承自BaseThing,它不是已经拥有Stuff 属性了吗?
  • 我也是这么想的。除非ChildTing 类之一覆盖或隐藏/隐藏它(以某种方式更改功能),否则如果它进入null,那么它实际上可能只是null
  • 另外,Helper.GetStuff(Name) 是否真的返回了一些东西?如果它返回一些东西,你是否 100% 确定它是Dictionary&lt;string, TElement&gt; 类型?如果不是,那么as 运算符将在您的构造函数中默认this.Stuffnull
  • 实际上我想我可能解释错了,因为我试图使其尽可能通用以避免使事情复杂化。这是在 MVC 的上下文中,让我更新它以更好地解释我正在尝试做什么
  • derviedOrBase.Stuff != null 或者我错过了什么?您能否发布您尝试在无法访问Stuff 的地方工作的代码?

标签: c# generics casting abstract-class


【解决方案1】:

很难编写从基类到泛型派生类之一的强类型代码。一种选择是使用dynamic 而不是强类型代码。

另一种选择是使用非泛型基类或接口,除非您需要使用特定类型的元素:

interface IHasTheStuff
{
  bool HaveStuff();
}

public abstract class BaseController<TElement> : IHasTheStuff, Controller ...
{
   ...
   public bool HaveStuff() { return Stuff != null;}
}

当您将控制器转换为该接口时:

Controller justController...
if (((IHasTheStuff)justController).HaveStuff())...

【讨论】:

  • @Josh - 关于动态/反射 - 查看 Eric Lippert 的回答:stackoverflow.com/questions/4646786/…。我会选择带有基类/接口的静态类型路由。
  • 使用界面非常完美,我可以毫无问题地将其投射到该界面,感谢这看起来像个技巧!
  • @josh 我的秘诀是避免感觉像 C&lt;T1&gt;C&lt;T2&gt; 这样的 2 个泛型类型从继承的角度来看有一些共同点(如果你有一些共同点,这尤其诱人基础class C&lt;T&gt; : Base) - 实际上它们的相关性不超过 2 个单独的类。如果您将它们想象为class C_T1 : Baseclass C_T2 : Base,您可能会更好地了解哪些演员表有意义,哪些没有。
  • 顺便说一句,方差可能不适用于您的情况。对于像 MVC 控制器这样涉及的代码,您通常需要完整类型(因为方差需要接口类型),或者即使您设法将自己限制为接口,您最终也需要在类型参数上同时使用 inout
  • 非常感谢您提供的额外见解,我认为在这种情况下它很简单,但我相信这会一次又一次地出现
猜你喜欢
  • 1970-01-01
  • 2014-09-22
  • 1970-01-01
  • 2015-02-13
  • 1970-01-01
  • 1970-01-01
  • 2017-09-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多