如何在使用通用约束时使用继承

Ian*_*Ian 7 c# generics inheritance

在尝试实现允许继承并希望有人可以提供帮助的库时,我正在努力解决一些通用约束问题.

我正在尝试建立一个有三种口味的类库,每个库都建立在另一个之上.对我来说,这似乎是一个使用泛型的绝佳机会,因为我不能通过纯粹的继承做我想做的事.下面的代码(这应该直接粘贴到VS)后面有一些解释:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test
{
    #region Base Classes

    public class GenericElement { }

    /// <summary>Visit to a GenericElement</summary>
    public class Generic_Visit<E> where E : GenericElement
    {
        public E Element { get; set; }
    }

    /// <summary>Collection of Visits</summary>
    public class Generic_Route<V, E>
        where V : Generic_Visit<E>
        where E : GenericElement
    {
        public List<V> Visits { get; set; }
        public Double Distance { get; set; }
    }

    /// <summary>Collection of Routes</summary>
    public class Generic_Solution<R, V, E>
        where R : Generic_Route<V, E>
        where V : Generic_Visit<E>
        where E : GenericElement
    {
        public List<R> Routes { get; set; }

        public Double Distance
        {
            get
            {
                return this.Routes.Select(r => r.Distance).Sum();
            }
        }
    }

    #endregion

    #region TSP Classes

    public class Concrete_TSPNode : GenericElement { }

    public abstract class Generic_TSPVisit<E> : Generic_Visit<E>
        where E : Concrete_TSPNode
    {
        public Double Time { get; set; }
    }

    public abstract class Generic_TSPRoute<V, E> : Generic_Route<V, E>
        where V : Concrete_TSPVisit
        where E : Concrete_TSPNode
    {
        public Double Time
        {
            get
            {
                return this.Visits.Select(v => v.Time).Sum();
            }
        }
    }

    public abstract class Generic_TSPSolution<R, V, E> : Generic_Solution<R, V, E>
        where R : Concrete_TSPRoute
        where V : Concrete_TSPVisit
        where E : Concrete_TSPNode
    {
        public Double Time
        {
            get
            {
                return this.Routes.Select(r => r.Time).Sum();
            }
        }
    }

    public class Concrete_TSPVisit : Generic_TSPVisit<Concrete_TSPNode> { }

    public class Concrete_TSPRoute : Generic_TSPRoute<Concrete_TSPVisit, Concrete_TSPNode> { }

    public class Concrete_TSPSolution : Generic_TSPSolution<Concrete_TSPRoute, Concrete_TSPVisit, Concrete_TSPNode> { }

    #endregion

    #region VRP

    public class Concrete_VRPNode : Concrete_TSPNode { }

    public abstract class Generic_VRPVisit<E> : Generic_TSPVisit<E> where E : Concrete_VRPNode
    {
        public Double Capacity { get; set; }
    }

    public abstract class Generic_VRPRoute<V, E> : Generic_TSPRoute<V, E>
        where V : Concrete_VRPVisit
        where E : Concrete_VRPNode
    {
        public Double Capacity
        {
            get
            {
                return this.Visits.Select(v => v.Capacity).Sum();
            }
        }
    }

    public abstract class G_VRPSolution<R, V, E> : Generic_TSPSolution<R, V, E>
        where R : Concrete_VRPRoute
        where V : Concrete_VRPVisit
        where E : Concrete_VRPNode
    {
        public Double Capacity
        {
            get
            {
                return this.Routes.Select(r => r.Capacity).Sum();
            }
        }
    }

    public class Concrete_VRPVisit : Generic_VRPVisit<Concrete_VRPNode> { }

    public class Concrete_VRPRoute : Generic_VRPRoute<Concrete_VRPVisit, Concrete_VRPNode> { }

    public class Concrete_VRPSolution : Generic_TSPSolution<Concrete_VRPRoute, Concrete_VRPVisit, Concrete_VRPNode> { }

    #endregion
}
Run Code Online (Sandbox Code Playgroud)

代码背后的想法是有一组基类使用泛型公开属性.这允许我拥有强类型集合.

这三个阶段中有2个基于这些,TSP和VRP在这个例子中有4个具体的类(这些是使用类库的开发人员应该与之交互,因为通用约束只是有点疯狂) - 元素,参观,路线和解决方案.

对于TSP和VRP,还有一些前缀为Generic的类.这些允许我想要的继承,因为它暴露了通用类型.如果我不使用这些(比如Concrete_VRPRoute继承Concrete_TSPRoute),那么我必须继续强制转换Visits集合返回的项目类型以获取Capacity属性.

我相当自信所有类型都正确排列,但是当我尝试构建时,我得到以下错误,我真的不知道如何解决它们.

错误1类型"V"不能用作泛型类型或方法"Test.Generic_Route"中的类型参数"V".没有从'V'到'Test.Generic_Visit'的隐式引用转换.

错误2类型"V"不能用作泛型类型或方法"Test.Generic_Solution"中的类型参数"V".没有从'V'到'Test.Generic_Visit'的隐式引用转换.

错误3类型"R"不能用作泛型类型或方法"Test.Generic_Solution"中的类型参数"R".没有从'R'到'Test.Generic_Route'的隐式引用转换

错误4类型"V"不能用作泛型类型或方法"Test.Generic_TSPRoute"中的类型参数"V".没有从'V'到'Test.Concrete_TSPVisit'的隐式引用转换.

错误5类型"V"不能用作泛型类型或方法"Test.Generic_TSPSolution"中的类型参数"V".没有从'V'到'Test.Concrete_TSPVisit'的隐式引用转换.

错误6类型"R"不能在泛型类型或方法"Test.Generic_TSPSolution"中用作类型参数"R".没有从'R'到'Test.Concrete_TSPRoute'的隐式引用转换.

错误7类型'Test.Concrete_VRPVisit'不能在泛型类型或方法'Test.Generic_TSPSolution'中用作类型参数'V'.没有从'Test.Concrete_VRPVisit'到'Test.Concrete_TSPVisit'的隐式引用转换.

错误8"Test.Concrete_VRPRoute"类型不能在泛型类型或方法"Test.Generic_TSPSolution"中用作类型参数"R".没有从'Test.Concrete_VRPRoute'到'Test.Concrete_TSPRoute'的隐式引用转换.'Test.Concrete_TSPRoute'.

Eni*_*ity 6

这是一块通用蛋糕.您需要根据自己定义泛型类.递归通用定义.

基础类:

public class Generic_Element<E>
    where E : Generic_Element<E>
{
}

/// <summary>Visit to a Generic_Element</summary>
public class Generic_Visit<V, E>
    where V : Generic_Visit<V, E>
    where E : Generic_Element<E>
{
    public E Element { get; set; }
}

/// <summary>Collection of Visits</summary>
public class Generic_Route<R, V, E>
    where R : Generic_Route<R, V, E>
    where V : Generic_Visit<V, E>
    where E : Generic_Element<E>
{
    public List<V> Visits { get; set; }
    public Double Distance { get; set; }
}

/// <summary>Collection of Routes</summary>
public class Generic_Solution<S, R, V, E>
    where S : Generic_Solution<S, R, V, E>
    where R : Generic_Route<R, V, E>
    where V : Generic_Visit<V, E>
    where E : Generic_Element<E>
{
    public List<R> Routes { get; set; }

    public Double Distance
    {
        get
        {
            return this.Routes.Select(r => r.Distance).Sum();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

TSP课程:

public class Generic_Tsp_Element<E> : Generic_Element<E>
where E : Generic_Tsp_Element<E>
{
}

/// <summary>Visit to a Generic_Element</summary>
public class Generic_Tsp_Visit<V, E> : Generic_Visit<V, E>
    where V : Generic_Tsp_Visit<V, E>
    where E : Generic_Tsp_Element<E>
{
    public Double Time { get; set; }
}

/// <summary>Collection of Visits</summary>
public class Generic_Tsp_Route<R, V, E> : Generic_Route<R, V, E>
    where R : Generic_Tsp_Route<R, V, E>
    where V : Generic_Tsp_Visit<V, E>
    where E : Generic_Tsp_Element<E>
{
    public Double Time
    {
        get
        {
            return this.Visits.Select(v => v.Time).Sum();
        }
    }
}

/// <summary>Collection of Routes</summary>
public class Generic_Tsp_Solution<S, R, V, E> : Generic_Solution<S, R, V, E>
    where S : Generic_Tsp_Solution<S, R, V, E>
    where R : Generic_Tsp_Route<R, V, E>
    where V : Generic_Tsp_Visit<V, E>
    where E : Generic_Tsp_Element<E>
{
    public Double Time
    {
        get
        {
            return this.Routes.Select(r => r.Time).Sum();
        }
    }
}

public class Concrete_Tsp_Element : Generic_Tsp_Element<Concrete_Tsp_Element> { }

public class Concrete_Tsp_Visit : Generic_Tsp_Visit<Concrete_Tsp_Visit, Concrete_Tsp_Element> { }

public class Concrete_Tsp_Route : Generic_Tsp_Route<Concrete_Tsp_Route, Concrete_Tsp_Visit, Concrete_Tsp_Element> { }

public class Concrete_Tsp_Solution : Generic_Tsp_Solution<Concrete_Tsp_Solution, Concrete_Tsp_Route, Concrete_Tsp_Visit, Concrete_Tsp_Element> { }
Run Code Online (Sandbox Code Playgroud)

VRP课程:

public class Generic_Vrp_Element<E> : Generic_Element<E>
where E : Generic_Vrp_Element<E>
{
}

/// <summary>Visit to a Generic_Element</summary>
public class Generic_Vrp_Visit<V, E> : Generic_Visit<V, E>
    where V : Generic_Vrp_Visit<V, E>
    where E : Generic_Vrp_Element<E>
{
    public Double Capacity { get; set; }
}

/// <summary>Collection of Visits</summary>
public class Generic_Vrp_Route<R, V, E> : Generic_Route<R, V, E>
    where R : Generic_Vrp_Route<R, V, E>
    where V : Generic_Vrp_Visit<V, E>
    where E : Generic_Vrp_Element<E>
{
    public Double Capacity
    {
        get
        {
            return this.Visits.Select(v => v.Capacity).Sum();
        }
    }
}

/// <summary>Collection of Routes</summary>
public class Generic_Vrp_Solution<S, R, V, E> : Generic_Solution<S, R, V, E>
    where S : Generic_Vrp_Solution<S, R, V, E>
    where R : Generic_Vrp_Route<R, V, E>
    where V : Generic_Vrp_Visit<V, E>
    where E : Generic_Vrp_Element<E>
{
    public Double Capacity
    {
        get
        {
            return this.Routes.Select(r => r.Capacity).Sum();
        }
    }
}

public class Concrete_Vrp_Element : Generic_Vrp_Element<Concrete_Vrp_Element> { }

public class Concrete_Vrp_Visit : Generic_Vrp_Visit<Concrete_Vrp_Visit, Concrete_Vrp_Element> { }

public class Concrete_Vrp_Route : Generic_Vrp_Route<Concrete_Vrp_Route, Concrete_Vrp_Visit, Concrete_Vrp_Element> { }

public class Concrete_Vrp_Solution : Generic_Vrp_Solution<Concrete_Vrp_Solution, Concrete_Vrp_Route, Concrete_Vrp_Visit, Concrete_Vrp_Element> { }
Run Code Online (Sandbox Code Playgroud)

最终结果是非通用的具体类,可以像这样使用:

var e = new Concrete_Tsp_Element();
var v = new Concrete_Tsp_Visit();
v.Element = e;
v.Time = 0.5;
var r = new Concrete_Tsp_Route();
r.Visits = new List<Concrete_Tsp_Visit>(new[] { v });
r.Distance = 2.1;
var s = new Concrete_Tsp_Solution();
s.Routes = new List<Concrete_Tsp_Route>(new[] { r });
Console.WriteLine(s.Distance);
Console.WriteLine(s.Time);
Console.ReadLine();
Run Code Online (Sandbox Code Playgroud)

请享用!请享用!