如何使用泛型约束时使用继承 [英] How to use Inheritance when using Generic Constraints

查看:130
本文介绍了如何使用泛型约束时使用继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我与一些通用的约束问题,努力实现一个库,允许继承,并希望有人能够帮助苦苦挣扎的时候。



我想建立一个具有3口味吧,在其他顶级每栋楼一个类库。对我来说,这似乎是使用泛型,我不能完全做我想做的纯通过继承的绝佳机会。该代码是以下(这应该直接粘贴到VS)的一些解释算账:

 使用系统; 
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;

命名空间测试
{
#地区的基类

公共类GenericElement {}

///<总结> ;参观一个GenericElement< /总结>
公共类Generic_Visit< E>其中E:GenericElement
{
公共E元素{搞定;组; }
}

///<总结>访问次数和LT收集; /总结>
公共类Generic_Route< V,E>
其中V:Generic_Visit< E>
,其中E:GenericElement
{
公开名单< V>访问{搞定;组; }
公共双距离{搞定;组; }
}

///<总结>路线及LT收集; /总结>
公共类Generic_Solution< R,V,E>
其中R:Generic_Route< V,E>
其中V:Generic_Visit< E>
,其中E:GenericElement
{
公开名单< R>路线{搞定;组; }

公共双距离
{
得到
{
返回this.Routes.Select(R = GT; r.Distance).SUM() ;
}
}
}

#endregion

#地区的TSP类

公共类Concrete_TSPNode:GenericElement {}

公共抽象类Generic_TSPVisit< E> :Generic_Visit< E>
,其中E:Concrete_TSPNode
{
公共双时{搞定;组; }
}

公共抽象类Generic_TSPRoute< V,E> :Generic_Route< V,E>
其中V:Concrete_TSPVisit
,其中E:Concrete_TSPNode
{
公共双时
{
得到
{
返回这一点。 Visits.Select(v => v.Time).SUM();
}
}
}

公共抽象类Generic_TSPSolution< R,V,E> :Generic_Solution< R,V,E>
其中R:Concrete_TSPRoute
其中V:Concrete_TSPVisit
,其中E:Concrete_TSPNode
{
公共双时
{
的get
{
返回this.Routes.Select(R = GT; r.Time).SUM();
}
}
}

公共类Concrete_TSPVisit:Generic_TSPVisit< Concrete_TSPNode> {}

公共类Concrete_TSPRoute:Generic_TSPRoute< Concrete_TSPVisit,Concrete_TSPNode> {}

公共类Concrete_TSPSolution:Generic_TSPSolution< Concrete_TSPRoute,Concrete_TSPVisit,Concrete_TSPNode> {}

#endregion

#地区的VRP

公共类Concrete_VRPNode:Concrete_TSPNode {}

公共抽象类Generic_VRPVisit< ; E> :Generic_TSPVisit< E>其中E:Concrete_VRPNode
{
公共双倍容量{搞定;组; }
}

公共抽象类Generic_VRPRoute< V,E> :Generic_TSPRoute< V,E>
其中V:Concrete_VRPVisit
,其中E:Concrete_VRPNode
{
公共双倍容量
{
得到
{
返回这一点。 Visits.Select(v => v.Capacity).SUM();
}
}
}

公共抽象类G_VRPSolution< R,V,E> :Generic_TSPSolution< R,V,E>
其中R:Concrete_VRPRoute
其中V:Concrete_VRPVisit
,其中E:Concrete_VRPNode
{
公共双倍容量
{
的get
{
返回this.Routes.Select(R = GT; r.Capacity).SUM();
}
}
}

公共类Concrete_VRPVisit:Generic_VRPVisit< Concrete_VRPNode> {}

公共类Concrete_VRPRoute:Generic_VRPRoute< Concrete_VRPVisit,Concrete_VRPNode> {}

公共类Concrete_VRPSolution:Generic_TSPSolution< Concrete_VRPRoute,Concrete_VRPVisit,Concrete_VRPNode> {}

#endregion
}



背后的想法代码是,有一组公开使用泛型性质的基类。这让我有例如强类型集合。



有那么2的3个阶段建立在这些,TSP和VRP的例子有4个具体类(这些都是使用类库开发者应为一般限制只得到可交互的有点疯狂) - 元素,参观,路线和解决方案。



有也一些类前缀一般为TSP和VRP。这让我想,因为它暴露了泛型类型的继承。如果我不使用这些(说Concrete_VRPRoute继承Concrete_TSPRoute),那么我必须保持铸造的访问返回集合拿到例如容量物业项目的类型。



我相当有信心,所有类型的正确排列,但是当我尝试建立我碰到下面的错误,我真的不知道该如何处理它们。



<块引用>

错误1类型V不能被用作在通用类型
或方法'Test.Generic_Route'
型参数V。
有一个从'V'的隐式引用
转换为
'Test.Generic_Visit。



错误2的
型V不能在通用型或
法被用作类型
参数V' Test.Generic_Solution。
有一个从'V'的隐式引用
转换为
'Test.Generic_Visit。



错误3
型R不能被用作在通用型或
法类型
参数R' Test.Generic_Solution。
有一个从'R'的隐式引用
转换为
'Test.Generic_Route



错误4类型V不能用作在通用类型
或方法
位Test.Generic_TSPRoute'
型参数V。有

'V'到'Test.Concrete_TSPVisit'隐式引用转换。



错误5的类型V不能在通用类型
或方法
用作
型参数V' Test.Generic_TSPSolution。
有一个从'V'的隐式引用
转换为
'Test.Concrete_TSPVisit。



错误6
型R不能被用作在通用型或
法$类型
参数R b $ b'Test.Generic_TSPSolution。
没有隐含的参考
转换,从'R'到
'Test.Concrete_TSPRoute。



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



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



解决方案

这是一块普通的蛋糕。你需要对自己的角度来定义泛型类。 。递归通用定义



基类:

 公共类Generic_Element< ; E> 
其中E:Generic_Element< E>
{
}

///<总结>参观一个Generic_Element< /总结>
公共类Generic_Visit< V,E>
其中V:Generic_Visit< V,E>
其中E:Generic_Element< E>
{
公共E元素{搞定;组; }
}

///<总结>访问次数和LT收集; /总结>
公共类Generic_Route< R,V,E>
其中R:Generic_Route< R,V,E>
其中V:Generic_Visit< V,E>
其中E:Generic_Element< E>
{
公开名单< V>访问{搞定;组; }
公共双距离{搞定;组; }
}

///<总结>路线及LT收集; /总结>
公共类Generic_Solution< S,R,V,E>
其中S:Generic_Solution< S,R,V,E>
其中R:Generic_Route< R,V,E>
其中V:Generic_Visit< V,E>
其中E:Generic_Element< E>
{
公开名单< R>路线{搞定;组; }

公共双距离
{
得到
{
返回this.Routes.Select(R = GT; r.Distance).SUM() ;
}
}
}



TSP类:

 公共类Generic_Tsp_Element< E> :Generic_Element< E> 
其中E:Generic_Tsp_Element< E>
{
}

///<总结>参观一个Generic_Element< /总结>
公共类Generic_Tsp_Visit< V,E> :Generic_Visit< V,E>
其中V:Generic_Tsp_Visit< V,E>
其中E:Generic_Tsp_Element< E>
{
公共双时{搞定;组; }
}

///<总结>访问次数和LT收集; /总结>
公共类Generic_Tsp_Route< R,V,E> :Generic_Route< R,V,E>
其中R:Generic_Tsp_Route< R,V,E>
其中V:Generic_Tsp_Visit< V,E>
其中E:Generic_Tsp_Element< E>
{
公共双时
{
得到
{
返回this.Visits.Select(V => v.Time).SUM() ;
}
}
}

///<总结>路线及LT收集; /总结>
公共类Generic_Tsp_Solution< S,R,V,E> :Generic_Solution< S,R,V,E>
其中S:Generic_Tsp_Solution< S,R,V,E>
其中R:Generic_Tsp_Route< R,V,E>
其中V:Generic_Tsp_Visit< V,E>
其中E:Generic_Tsp_Element< E>
{
公共双时
{
得到
{
返回this.Routes.Select(R = GT; r.Time).SUM() ;
}
}
}

公共类Concrete_Tsp_Element:Generic_Tsp_Element< Concrete_Tsp_Element> {}

公共类Concrete_Tsp_Visit:Generic_Tsp_Visit< Concrete_Tsp_Visit,Concrete_Tsp_Element> {}

公共类Concrete_Tsp_Route:Generic_Tsp_Route< Concrete_Tsp_Route,Concrete_Tsp_Visit,Concrete_Tsp_Element> {}

公共类Concrete_Tsp_Solution:Generic_Tsp_Solution< Concrete_Tsp_Solution,Concrete_Tsp_Route,Concrete_Tsp_Visit,Concrete_Tsp_Element> {}



VRP类:

 公共类Generic_Vrp_Element< E> :Generic_Element< E> 
其中E:Generic_Vrp_Element< E>
{
}

///<总结>参观一个Generic_Element< /总结>
公共类Generic_Vrp_Visit< V,E> :Generic_Visit< V,E>
其中V:Generic_Vrp_Visit< V,E>
其中E:Generic_Vrp_Element< E>
{
公共双倍容量{搞定;组; }
}

///<总结>访问次数和LT收集; /总结>
公共类Generic_Vrp_Route< R,V,E> :Generic_Route< R,V,E>
其中R:Generic_Vrp_Route< R,V,E>
其中V:Generic_Vrp_Visit< V,E>
其中E:Generic_Vrp_Element< E>
{
公共双倍容量
{
得到
{
返回this.Visits.Select(V => v.Capacity).SUM() ;
}
}
}

///<总结>路线及LT收集; /总结>
公共类Generic_Vrp_Solution< S,R,V,E> :Generic_Solution< S,R,V,E>
其中S:Generic_Vrp_Solution< S,R,V,E>
其中R:Generic_Vrp_Route< R,V,E>
其中V:Generic_Vrp_Visit< V,E>
其中E:Generic_Vrp_Element< E>
{
公共双倍容量
{
得到
{
返回this.Routes.Select(R = GT; r.Capacity).SUM() ;
}
}
}

公共类Concrete_Vrp_Element:Generic_Vrp_Element< Concrete_Vrp_Element> {}

公共类Concrete_Vrp_Visit:Generic_Vrp_Visit< Concrete_Vrp_Visit,Concrete_Vrp_Element> {}

公共类Concrete_Vrp_Route:Generic_Vrp_Route< Concrete_Vrp_Route,Concrete_Vrp_Visit,Concrete_Vrp_Element> {}

公共类Concrete_Vrp_Solution:Generic_Vrp_Solution< Concrete_Vrp_Solution,Concrete_Vrp_Route,Concrete_Vrp_Visit,Concrete_Vrp_Element> {}



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

 变种E =新Concrete_Tsp_Element(); 
变种V =新Concrete_Tsp_Visit();
v.Element = E;
v.Time = 0.5;
变种R =新Concrete_Tsp_Route();
r.Visits =新的List< Concrete_Tsp_Visit>(新[] {V});
r.Distance = 2.1;
变种S =新Concrete_Tsp_Solution();
s.Routes =新的List< Concrete_Tsp_Route>(新[] {R});
Console.WriteLine(s.Distance);
Console.WriteLine(s.Time);
到Console.ReadLine();



尽情享受吧!
尽情享受吧!


I'm struggling with some Generic constraint issues when trying to implement a library that allows inheritance and hoping someone can help.

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:

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
}

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.

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.

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.

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.

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'.

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'.

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'

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'.

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'.

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'.

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'.

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'.

解决方案

It's a piece of generic cake. You need to define the generic classes in terms of themselves. A recursive generic definition.

Base Classes:

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

TSP Classes:

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

VRP Classes:

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

The final result is non-generic concrete classes that can be used like this:

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

Enjoy! Enjoy!

这篇关于如何使用泛型约束时使用继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆