I have the following classes
public abstract class BaseViewPresenter { } public abstract class BaseView<T> : UserControl where T : BaseViewPresenter { } public class LoginPresenter : BaseViewPresenter { } public partial class LoginView : BaseView<LoginPresenter> { }
I have a method that looks like this (simplified)
public BaseView<BaseViewPresenter> Resolve(BaseViewPresenter model) { var type = model.GetType(); var viewType = _dataTemplates[type]; // Correctly creates BaseView object var control = Activator.CreateInstance(viewType); // Fails to cast as BaseView<BaseViewPresenter> so returns null return control as BaseView<BaseViewPresenter>; }
When I call this using an instances of LoginPresenter
var login = new LoginPresenter(); var ctl = Resolve(login);
The line Activator.CreateInstance(viewType)
correctly resolves into a new instances of my LoginView
, however control as BaseView<BaseViewPresenter>
can't do the cast correctly so returns null
.
Is there a way to correctly cast the control
into BaseView<BaseViewPresenter>
without using specific type generics?
Since LoginView
inherits from BaseView<LoginPresenter>
, and LoginPresenter
inherits from BaseViewPresenter
, I would assume there's a way to convert LoginView
to BaseView<BaseViewPresenter>
.
I am stuck with using .Net 3.5
Q: Can you cast to an abstract class? A: Sure - of course you can. What you can't do is call an abstract method of an abstract class.
Press Ctrl+Shift+R and then choose Convert Interface to Abstract Class. Right-click and choose Refactor | Convert Interface to Abstract Class from the context menu.
The abstract type is often used as a return type (because you don't want the caller to know what concrete type is returned: it could change later, or could vary based on the arguments of the configuration).
Since you cannot instantiate an abstract class you cannot access its instance methods too. You can call only static methods of an abstract class (since an instance is not required).
This is a very frequently asked question. Let's rename your types:
abstract class Fruit { } // was BaseViewPresenter abstract class FruitBowl<T> where T : Fruit // was BaseView class Apple : Fruit { } // was LoginPresenter class BowlOfApples : FruitBowl<Apple> { } // was LoginView
Your question now is:
I have a
BowlOfApples
, which inherits fromFruitBowl<Apple>
. Why can I not use it as aFruitBowl<Fruit>
? An apple is a fruit, so a bowl of apples is a bowl of fruit.
No, it isn't. You can put a banana in a bowl of fruit, but you can't put a banana in a bowl of apples, and therefore a bowl of apples is not a bowl of fruit. (And by similar argument, a bowl of fruit is not a bowl of apples either.) Since the operations you can legally perform on the two types are different, they cannot be compatible.
Here is a photo of StackOverflow legend Jon Skeet demonstrating this fact:
The feature you want is called generic contravariance, and it is supported only on interfaces and delegate types when the compiler can prove that the variance is safe, and when the varying type is a reference type. For example, you can use an IEnumerable<Apple>
in a context where IEnumerable<Fruit>
is needed because the compiler can verify that there is no way that you can put a Banana
into a sequence of fruit.
Do a search on "C# covariance and contravariance" on this site or on the web and you'll find many more details about how this feature works. In particular, my series of articles on how we designed and implemented this feature in C# 4 starts here: http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx
I accepted Eric's answer since it provides a great explanation of why what I wanted wasn't possible, but I also thought I'd share my solution in case anyone else runs into this same problem.
I removed the generic type parameter from my original BaseView
class, and created a 2nd version of the BaseView
class that included the generic type parameter and specifics for it.
The first version is used by my .Resolve()
method or other code that doesn't care about the specific types, and the second version is used by any code that does care, such as the implentation of a BaseView
Here's an example of how my code ended up looking
// base classes public abstract class BaseViewPresenter { } public abstract class BaseView : UserControl { public BaseViewPresenter Presenter { get; set; } } public abstract class BaseView<T> : BaseView where T : BaseViewPresenter { public new T Presenter { get { return base.Presenter as T; } set { base.Presenter = value; } } } // specific classes public class LoginPresenter : BaseViewPresenter { } public partial class LoginView : BaseView<LoginPresenter> { // Can now call things like Presenter.LoginPresenterMethod() } // updated .Resolve method used for obtaining UI object public BaseView Resolve(BaseViewPresenter presenter) { var type = model.GetType(); var viewType = _dataTemplates[type]; BaseView view = Activator.CreateInstance(viewType) as BaseView; view.Presenter = presenter; return view; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With