代码之家  ›  专栏  ›  技术社区  ›  Ian

使用泛型约束时如何使用继承

  •  7
  • Ian  · 技术社区  · 15 年前

    当我试图实现一个允许继承的库并希望有人能提供帮助时,我正在努力解决一些通用的约束问题。

    我正试图建立一个类库,它有3种风格,每一个建筑在其他之上。对我来说,这似乎是一个使用泛型的绝佳机会,因为我不能完全通过纯继承来做我想做的事情。代码如下(这应该直接粘贴到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
    }
    

    我很有信心所有类型都是正确的,但是当我尝试构建时,我会遇到以下错误,我真的不知道如何处理它们。

    错误1类型“V”不能用作 泛型类型中的类型参数“V” '或方法'测试.u路径'. 没有隐含的引用 从“V”转换为

    错误2 类型“V”不能用作类型 泛型类型中的参数“V”或 '方法'Test.u解决方案'. 没有隐含的引用

    类型“R”不能用作类型 泛型类型中的参数“R”或 '方法'Test.u解决方案'. 没有隐含的引用 '测试.u路径'

    错误4类型“V”不能用作 或方法 没有来自的隐式引用转换 “V”到“V”混凝土试验'.

    错误5类型“V”不能用作 或方法 '测试通用解决方案'. 从“V”转换为 '混凝土试验'.

    错误6 类型“R”不能用作类型 泛型类型中的参数“R”或 方法 没有隐含的引用 从“R”转换为 '混凝土试验项目'.

    '类型'混凝土试验'不能 泛型类型或方法 '测试通用解决方案'. 没有隐含的引用 转换自 '混凝土试验'.

    错误8 在中用作类型参数“R” 泛型类型或方法 转换自 '试验混凝土'到

    3 回复  |  直到 15 年前
        1
  •  6
  •   Enigmativity    15 年前

    基类:

    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();
            }
        }
    }
    

    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> { }
    

    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> { }
    

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

    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();
    

    好好享受!

        2
  •  2
  •   Timwi    15 年前

    好的,让我们检查一下第一个。错误是:

    类型“V”不能用作泛型类型或方法中的类型参数“V”测试.u路径'. 没有从“V”到“V”的隐式引用转换Test.u访问'.

    它抱怨这个声明:

    public abstract class Generic_TSPRoute<V, E> : Generic_Route<V, E>
        where V : Concrete_TSPVisit
        where E : Concrete_TSPNode
    

    这确立了两个定义:

    • V 是一个 Concrete_TSPVisit (或其后代)

    • E 是一个 Concrete_TSPNode

    现在让我们看看 Generic_Route<V, E> 让我们加入:

    public class Generic_Route<V, E>
        where V : Generic_Visit<E>
        where E : GenericElement
    

    第二个约束很好,因为 是一个 GenericElement 是一个 混凝土节点 因此 Generic_Visit<E>

    • Generic_Visit<Concrete_TSPNode> ,

    • Generic_Visit<some subclass of Concrete_TSPNode>

    然而,我们也从前面知道 混凝土路面 (或它的后代)。

    • 继承自 Generic_TSPVisit<Concrete_TSPNode>

    • 通用\u TSPVisit<混凝土\u TSPNode> 继承自

    注意到什么了吗?这就要求它是一个 一般访问<混凝土> .

    想象一下我写下了这样的话:

    var route = new Generic_TSPRoute<Concrete_TSPVisit, Concrete_TSPNode_Subclass>();
    

    混凝土路面 是一个 一般访问<混凝土>

    public Concrete_TSPNode Element { get; set; }
    

    如果我从这个属性中检索一个值,它只能保证是一个 但不一定是 Concrete_TSPNode_Subclass .

    我留下这个答案,因为它解释了编译器错误的原因,但Enigmatitys的答案实际上提供了问题的解决方案。

        3
  •  0
  •   Timwi    15 年前

    这里的答案和谜一样,但是去掉了所有多余的约束。它仍然可以编译,它没有任何泛型递归,而且据我所知,它仍然是必需的类型安全的。神秘,我错过了什么?:)

    public class Generic_Element { }
    
    public class Generic_Visit<E>
    {
        public E Element { get; set; }
    }
    
    /// <summary>Collection of Visits</summary>
    public class Generic_Route<V>
    {
        public List<V> Visits { get; set; }
        public Double Distance { get; set; }
    }
    
    /// <summary>Collection of Routes</summary>
    public class Generic_Solution<R, V>
        where R : Generic_Route<V>
    {
        public List<R> Routes { get; set; }
    
        public Double Distance
        {
            get
            {
                return this.Routes.Select(r => r.Distance).Sum();
            }
        }
    }
    
    public class Generic_Tsp_Element : Generic_Element
    {
    }
    
    /// <summary>Visit to a Generic_Element</summary>
    public class Generic_Tsp_Visit<E> : Generic_Visit<E>
    {
        public Double Time { get; set; }
    }
    
    /// <summary>Collection of Visits</summary>
    public class Generic_Tsp_Route<V, E> : Generic_Route<V>
        where V : Generic_Tsp_Visit<E>
    {
        public Double Time
        {
            get
            {
                return this.Visits.Select(v => v.Time).Sum();
            }
        }
    }
    
    /// <summary>Collection of Routes</summary>
    public class Generic_Tsp_Solution<R, V, E> : Generic_Solution<R, V>
        where R : Generic_Tsp_Route<V, E>
        where V : Generic_Tsp_Visit<E>
    {
        public Double Time
        {
            get
            {
                return this.Routes.Select(r => r.Time).Sum();
            }
        }
    }
    
    public class Concrete_Tsp_Element : Generic_Tsp_Element { }
    
    public class Concrete_Tsp_Visit : Generic_Tsp_Visit<Concrete_Tsp_Element> { }
    
    public class Concrete_Tsp_Route : Generic_Tsp_Route<Concrete_Tsp_Visit, Concrete_Tsp_Element> { }
    
    public class Concrete_Tsp_Solution : Generic_Tsp_Solution<Concrete_Tsp_Route, Concrete_Tsp_Visit, Concrete_Tsp_Element> { }
    
    public class Generic_Vrp_Element : Generic_Element
    {
    }
    
    /// <summary>Visit to a Generic_Element</summary>
    public class Generic_Vrp_Visit<V, E> : Generic_Visit<E>
    {
        public Double Capacity { get; set; }
    }
    
    /// <summary>Collection of Visits</summary>
    public class Generic_Vrp_Route<R, V, E> : Generic_Route<V>
        where V : Generic_Vrp_Visit<V, 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<R, V>
        where R : Generic_Vrp_Route<R, V, E>
        where V : Generic_Vrp_Visit<V, E>
    {
        public Double Capacity
        {
            get
            {
                return this.Routes.Select(r => r.Capacity).Sum();
            }
        }
    }
    
    public class Concrete_Vrp_Element : Generic_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> { }