I'll let the code do the talking:
using System.Collections.Generic;
namespace test
{
public interface IThing { } // can't change this - it's a 3rd party thing
public interface IThingRepository<T> where T : class, IThing { } // can't change this - it's a 3rd party thing
public interface IThingServiceInstance<T>
where T : class, IThing
{
IThingRepository<T> Repository { get; set; }
}
public class ThingServiceInstance<T> : IThingServiceInstance<T> where T : class, IThing
{
public IThingRepository<T> Repository { get; set; }
}
public class MyThing : IThing
{
}
class Test
{
public void DoStuff()
{
IList<IThingServiceInstance<IThing>> thingServiceInstances = new List<IThingServiceInstance<IThing>>();
// the following line does not compile. Errors are:
// 1: The best overloaded method match for 'System.Collections.Generic.ICollection<test.IThingServiceInstance<test.IThing>>.Add(test.IThingServiceInstance<test.IThing>)' has some invalid arguments C:\TFS\FACE\ResearchArea\ArgonServiceBusSpike\Argon_Service_Bus_Spike_v2\Argon.ServiceLayer\test.cs 31 13 Argon.ServiceGateway
// 2: Argument 1: cannot convert from 'test.ThingServiceInstance<test.MyThing>' to 'test.IThingServiceInstance<test.IThing>' C:\TFS\FACE\ResearchArea\ArgonServiceBusSpike\Argon_Service_Bus_Spike_v2\Argon.ServiceLayer\test.cs 31 39 Argon.ServiceGateway
// Why? ThingServiceInstance is an IThingServiceInstance and MyThing is an IThing
thingServiceInstances.Add(new ThingServiceInstance<MyThing>());
}
}
}
If ThingServiceInstance
is an IThingServiceInstance
and MyThing
is an IThing
, why can't I add a ThingServiceInstance<MyThing
> to a collection of IThingServiceInstance<IThing>
?
What can I do to make this code compile?
ThingServiceInstance<MyThing>
is NOT a subtype of IThingServiceInstance<IMyThing>
, because IThingServiceInstance<T>
is invariant in its type parameter <T>
.
If you wanna make ThingServiceInstance<MyThing>
a subtype of IThingServiceInstance<IMyThing>
, then T
has to be covariant.
In C#, you do that by declaring IThingServiceInstance<T>
as such:
public interface IThingServiceInstance<out T>
Edit
This, however implies that ThingServiceInstance<T>
can only return instances of T, but never have them as method arguments (hence the "out" notation).
Edit2
This is the gist of why your code wasn't compiling. As pointed out, since your ThingServiceInstance<T>
exposes an IThingRepository<T>
property, that too has to be covariant like so:
public interface IThingRepository<out T> where T : class, IThing { }
As follows, your property has to be get-only (remember, you can only return instances of T
, or U<T>
for that matter).
You can get it to compile if you declare two of the interfaces coariant, and remove the setter from IThingServiceInstance
.
Of course, you can't change the third party interface, so this doesn't really help.
public interface IThingRepository<out T> where T : class, IThing { } // can't change this - it's a 3rd party thing
public interface IThingServiceInstance<out T>
where T : class, IThing
{
IThingRepository<T> Repository { get; }
}
If IThingRepository<T>
does not declare T
covariant, then for
T : A
you don't get
IThingRepository<T> : IThingRespository<A>
and so you cannot have
IThingServiceInstance<T> : IThingServiceInstance<A>
since the type returned by the getter are not "compatible".
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