Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to use Inheritance when using Generic Constraints
    text
    copied!<p>I'm struggling with some Generic constraint issues when trying to implement a library that allows inheritance and hoping someone can help. </p> <p>I'm trying to build up a class library that has 3 flavours to it, each building on top of the other. To me it seemed like a perfect opportunity to use Generics as I can't quite do what I want through pure inheritance. The code's below (this should paste straight into VS) with some explanation afterwards:</p> <pre><code>using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Test { #region Base Classes public class GenericElement { } /// &lt;summary&gt;Visit to a GenericElement&lt;/summary&gt; public class Generic_Visit&lt;E&gt; where E : GenericElement { public E Element { get; set; } } /// &lt;summary&gt;Collection of Visits&lt;/summary&gt; public class Generic_Route&lt;V, E&gt; where V : Generic_Visit&lt;E&gt; where E : GenericElement { public List&lt;V&gt; Visits { get; set; } public Double Distance { get; set; } } /// &lt;summary&gt;Collection of Routes&lt;/summary&gt; public class Generic_Solution&lt;R, V, E&gt; where R : Generic_Route&lt;V, E&gt; where V : Generic_Visit&lt;E&gt; where E : GenericElement { public List&lt;R&gt; Routes { get; set; } public Double Distance { get { return this.Routes.Select(r =&gt; r.Distance).Sum(); } } } #endregion #region TSP Classes public class Concrete_TSPNode : GenericElement { } public abstract class Generic_TSPVisit&lt;E&gt; : Generic_Visit&lt;E&gt; where E : Concrete_TSPNode { public Double Time { get; set; } } public abstract class Generic_TSPRoute&lt;V, E&gt; : Generic_Route&lt;V, E&gt; where V : Concrete_TSPVisit where E : Concrete_TSPNode { public Double Time { get { return this.Visits.Select(v =&gt; v.Time).Sum(); } } } public abstract class Generic_TSPSolution&lt;R, V, E&gt; : Generic_Solution&lt;R, V, E&gt; where R : Concrete_TSPRoute where V : Concrete_TSPVisit where E : Concrete_TSPNode { public Double Time { get { return this.Routes.Select(r =&gt; r.Time).Sum(); } } } public class Concrete_TSPVisit : Generic_TSPVisit&lt;Concrete_TSPNode&gt; { } public class Concrete_TSPRoute : Generic_TSPRoute&lt;Concrete_TSPVisit, Concrete_TSPNode&gt; { } public class Concrete_TSPSolution : Generic_TSPSolution&lt;Concrete_TSPRoute, Concrete_TSPVisit, Concrete_TSPNode&gt; { } #endregion #region VRP public class Concrete_VRPNode : Concrete_TSPNode { } public abstract class Generic_VRPVisit&lt;E&gt; : Generic_TSPVisit&lt;E&gt; where E : Concrete_VRPNode { public Double Capacity { get; set; } } public abstract class Generic_VRPRoute&lt;V, E&gt; : Generic_TSPRoute&lt;V, E&gt; where V : Concrete_VRPVisit where E : Concrete_VRPNode { public Double Capacity { get { return this.Visits.Select(v =&gt; v.Capacity).Sum(); } } } public abstract class G_VRPSolution&lt;R, V, E&gt; : Generic_TSPSolution&lt;R, V, E&gt; where R : Concrete_VRPRoute where V : Concrete_VRPVisit where E : Concrete_VRPNode { public Double Capacity { get { return this.Routes.Select(r =&gt; r.Capacity).Sum(); } } } public class Concrete_VRPVisit : Generic_VRPVisit&lt;Concrete_VRPNode&gt; { } public class Concrete_VRPRoute : Generic_VRPRoute&lt;Concrete_VRPVisit, Concrete_VRPNode&gt; { } public class Concrete_VRPSolution : Generic_TSPSolution&lt;Concrete_VRPRoute, Concrete_VRPVisit, Concrete_VRPNode&gt; { } #endregion } </code></pre> <p>The idea behind the code is that there are a set of base classes that expose properties using Generics. This allows me to have strongly typed collections for example.</p> <p>There are then 2 of the 3 stages build upon these, TSP and VRP in the example which have 4 concrete classes (these are what the developer using the class library should be interacting with as the generic constraints just get a bit crazy) - Element, Visit, Route and Solution.</p> <p>There are also some classes prefixed Generic for both TSP and VRP. These allow the inheritance that I want as it exposes the Generic Types. If I don't use these (say Concrete_VRPRoute inherits Concrete_TSPRoute) then I have to keep casting the type of item returned by the Visits collection to get the Capacity property for example.</p> <p>I'm fairly confident all the types line up correctly, but when I try to build I get the following errors and I really don't know how to tackle them.</p> <blockquote> <p>Error 1 The type 'V' cannot be used as type parameter 'V' in the generic type or method 'Test.Generic_Route'. There is no implicit reference conversion from 'V' to 'Test.Generic_Visit'. </p> <p>Error 2 The type 'V' cannot be used as type parameter 'V' in the generic type or method 'Test.Generic_Solution'. There is no implicit reference conversion from 'V' to 'Test.Generic_Visit'. </p> <p>Error 3 The type 'R' cannot be used as type parameter 'R' in the generic type or method 'Test.Generic_Solution'. There is no implicit reference conversion from 'R' to 'Test.Generic_Route' </p> <p>Error 4 The type 'V' cannot be used as type parameter 'V' in the generic type or method 'Test.Generic_TSPRoute'. There is no implicit reference conversion from 'V' to 'Test.Concrete_TSPVisit'. </p> <p>Error 5 The type 'V' cannot be used as type parameter 'V' in the generic type or method 'Test.Generic_TSPSolution'. There is no implicit reference conversion from 'V' to 'Test.Concrete_TSPVisit'. </p> <p>Error 6 The type 'R' cannot be used as type parameter 'R' in the generic type or method 'Test.Generic_TSPSolution'. There is no implicit reference conversion from 'R' to 'Test.Concrete_TSPRoute'. </p> <p>Error 7 The type 'Test.Concrete_VRPVisit' cannot be used as type parameter 'V' in the generic type or method 'Test.Generic_TSPSolution'. There is no implicit reference conversion from 'Test.Concrete_VRPVisit' to 'Test.Concrete_TSPVisit'. </p> <p>Error 8 The type 'Test.Concrete_VRPRoute' cannot be used as type parameter 'R' in the generic type or method 'Test.Generic_TSPSolution'. There is no implicit reference conversion from 'Test.Concrete_VRPRoute' to 'Test.Concrete_TSPRoute'.'Test.Concrete_TSPRoute'. </p> </blockquote>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload