2

I have an abstract generic class that inherits from the Mvc Controller uses the generic type to create a dictionary of items, similar to this:

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

I then have several different implementations of BaseControllers that pass in different types of BaseElement, based on a criteria that names the object (I believe this part is irrelevant, but please let me know if it's affecting my end result).

The problem is later I need to check if the "Stuff" property is null from an actionfilter, which accesses instances of BaseController through the base Mvc Controller property.

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

My "BaseController" is a controller, so it does fit into that property, but I can't figure out how to cast it to my BaseController type to get the Stuff property...

Can this be done? I've seen while searching mention of covariance, but I can't seem to get my head around it, is that what I need to make this work?

I also saw using reflection as a solution but that is expensive and won't work for my particular situation.

finally I saw that this could work if I defined the base as an Interface instead of abstract class, but I need that base behavior as it will be shared across all inherited types...

The main reason I'm typing this question out is because SO always comes up with great similar questions and i usually just end up finding my answer, but this time I'm really lost with the covariance and generics, so I could use some insight as to whether or not this is even possible, or if I should be doing this in a completely different way...

SelAromDotNet
  • 4,715
  • 5
  • 37
  • 59
  • Maybe I'm having a slow moment. If `Thing` inherits from a `BaseThing`, wouldn't it already have the `Stuff` property? – Yuck Jan 28 '14 at 02:36
  • That's what I was thinking too. Unless one of the `ChildTing` classes overrides or shadows/hides it (changing the functionality in some way), then if it's coming in `null`, then it might actually just be `null`. – valverij Jan 28 '14 at 02:38
  • Also, is `Helper.GetStuff(Name)` actually returning something? And if it's returning something, are you 100% sure it is of type `Dictionary`? If it isn't, then the `as` operator will default `this.Stuff` to `null` in your constructor. – valverij Jan 28 '14 at 02:41
  • actually I think I may have explained this incorrectly as I was trying to make it as generic as possible to avoid complicating things. this is in the context of MVC, let me update it to better explain what I'm trying to do – SelAromDotNet Jan 28 '14 at 02:41
  • okay I updated the question, when in Mvc, I get the Controller in and it's an Mvc Controller, but it's also a BaseThing, how do I cast it in a generic way to BaseThing? can this be done? or do I have to if/then on all the possible inherited Things? – SelAromDotNet Jan 28 '14 at 02:45
  • Helper.GetStuff(Name) will ALWAYS return a string yes, but the GetStuff could fail, and return null. That's why I want to be able to cast the Controller to this base type and check if it is null. – SelAromDotNet Jan 28 '14 at 02:45
  • 1
    `derviedOrBase.Stuff != null` or I'm missing something? Could you please post code that you try to get working where you can't access `Stuff`? – Alexei Levenkov Jan 28 '14 at 02:50
  • updated, i'm trying to convert the Controller in an ActionFilter to my custom controller to check if stuff is null – SelAromDotNet Jan 28 '14 at 02:53

1 Answers1

3

It is hard to write strongly typed code that goes from base class to one of derived classes that are generic. One option is to use dynamic instead of strongly typed code.

Another option is to have non-generic base class or interface unless you need to work with elements of particular type:

interface IHasTheStuff
{
  bool HaveStuff();
}

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

And than when you have just controller cast to that interface:

Controller justController...
if (((IHasTheStuff)justController).HaveStuff())...
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • @Josh - on dynamic/reflection - check out Eric Lippert's answer : http://stackoverflow.com/questions/4646786/dynamic-lang-runtime-vs-reflection . I'd go for statically typed route with base class/interface. – Alexei Levenkov Jan 28 '14 at 03:06
  • using the interface was perfect, and allowed me to cast it to that interface without any problems, thanks this looks like the trick! – SelAromDotNet Jan 28 '14 at 03:08
  • @josh my inner trick for it is to avoid feeling that 2 generic types like `C` and `C` have something in common from inheritance point of view (which is especially tempting if you have some common base `class C : Base`) - in reality they are no more related than 2 separate classes. If you imagine them to be `class C_T1 : Base` and `class C_T2 : Base` you may get better sense of what casts would make sense and what not. – Alexei Levenkov Jan 28 '14 at 03:21
  • BTW, variance would probably not work in your case. For such involved code as MVC controller you usually need full types (because variance requires interface types) or even if you manage to limit yourself to interface you end up with need for both `in` and `out` on type argument. – Alexei Levenkov Jan 28 '14 at 03:25
  • thanks so much for the additional insight, i think in this case it was simple enough, but I'm sure this will come up again and again – SelAromDotNet Jan 28 '14 at 03:31