Reputation: 851
I am trying to use an interface based approach in an MVC application. However, I cannot pass my model (received from a form submission to an MVC action) to a method, instead it throws up an error saying
Cannot convert from Foo<Bar> to IFoo<IBar>
Edit: For those who rudely removed my complete question before I had a chance to update it based on comments here is an exact duplicate of the codeproject question that I had posted and thought it would make your lives easier to read there rather than here.
Hi All,
It's been a while since I've posted here but I'm having a bit of a mare and can't for the life of me remember what I'm doing wrong. I'm pretty sure it's fairly simple so hopefully you can help.
I have the following (approximated example):
public interface IFoo<T>
{ //...some other properties....
List<T> Bars {get;set;}
}
public interface IBar
{ //...some properties...
}
public class Foo : IFoo<Bar>
{ //...some properties...
List<Bar> Bars {get;set;}
}
public class Bar : IBar
{ //...some properties...
}
Then I have a helper class which looks a bit like this:
public interface IHelper
{
bool DoSomething(IFoo<IBar> model, string path);
}
public class Helper : IHelper
{
public bool DoSomething(IFoo<IBar> model, string path)
{
//..Save model to path
return true;
}
}
So, the issue I have is when I try to pass an instance of Foo to my helper method I get the error: Argumet type 'Foo' is no assignable to parameter type 'IFoo<IBar>'
I'm not sure why I get this error because Foo inherits from IFoo and Bar inherits from IBar.
Additional Info
This is how the Foo class is initially getting populated. It's a form submission from a webpage. If I try to declare Foo to be Foo: IFoo<IBar> I get the error: Cannot create an instance of an interface. upon form submission. This is an MVC generated error. As a result Foo is defined as above using IFoo<Bar>
[HttpPost]
public ActionResult RequestSubmission(Foo model)
{
if (ModelState.IsValid)
{
helper.DoSomething(model, Server.MapPath("/Assets/Template.docx"));
return Json(new {IsSuccess=true});
}
return PartialView("Form", model);
}
Bit of scope
This project is a basic MVC5 project with no authentication. I have a controller that, using a poor mans DI controller, is having the helper class injected into it. My MVC models inherit from the interfaces to allow them to be passed through.
So effectively Foo and Bar are data models.
This was all working before I tried to re-write it to use Interfaces, as tightly coupled I had no problems at all.
So, my question in summary:
Why do I get this error, and how can I resolve it?
If you need more information or clarification on anything just yell :)
Hope you can help.
In addition to this the following comment was made in response to the above question which changed the error:
You might need
Foo : IFoo<T> where T : IBar
Then use
Foo<Bar>
rather than just Foo
This resulted in the new error:
Cannot convert from Foo<Bar> to IFoo<IBar>
Now, in response to the comment about Covariance and contravariance , I had kind of come across it in my research of the problem but I didn't understand why it was relevant. My knowledge of "Generics" is limited and I thought that what I was doing was related to Interface and DI related elements.
I'm pretty sure some one will think it appropriate to edit this again but it now has everything someone who comes along to read it needs to know about what the issue is and what the solution was (as there is a marked answer).
For reference: This is where I first posted the question Original Question on Code Project
Upvotes: 0
Views: 523
Reputation: 11273
You can also do this with generic type conditions, for example, if you change your IHelper
to this:
public interface IHelper
{
bool DoSomething<T>(IFoo<T> model, string path) where T : IBar;
}
You can then implement it:
public class Helper : IHelper
{
public bool DoSomething<T>(IFoo<T> model, string path) where T : IBar
{
//..Save model to path
return true;
}
}
And calling
someHelperInstance.DoSomething(someInstanceOfFoo, somePath);
No longer throws that error. This is because you are constraining the generic IFoo<T>
to be any IBar
derived type. You may want to read up on covariance vs contravariance on MSDN.
Upvotes: 1