
在C#里,普通类和抽象类不支持协变,想要用协变得用接口。
所谓协变,比如有接口IA,及其子类AA
IA<BaseQueryInfo> a=new AA<MultiBorrowTag>() //OK,正确的协变。
AA<BaseQueryInfo> a=new AA<MultiBorrowTag>() //错误,不允许协变!
协变接口的定义:
interface IA<out T> //这个out很重要,表示这个接口支持协变。
{
void F(); //OK
T G();//OK,协变允许泛型形参作为返回值。
void H(T t);//错误,协变不允许泛型形参作为函数形参。
}
所以,解决方案一:在声明DataTagEnumQueryDict变量时,用DataProcessEntity的声明了out的父接口代替。比如假定有个接口IDataProcess<out T>
则声明为:
private static Dictionary<DataTagEnum, IDataProcess<BaseQueryInfo>> DataTagEnumQueryDict = new
解决方案二:
如果类DataProcessEntity压根不存在声明了out的父接口怎么办?没办法,只能都new DataProcessEntity<BaseQueryInfo> {}
解决方案三:如果你又不想new DataProcessEntity<BaseQueryInfo> {},怎么办?也有一种比较曲折的方法:
自己定义一个接口!
interface IDataProcessEntityDelegator<out T>
{
void AAA();//把想要用的DataProcessEntity的方法签名原样抄下来,但千万不要抄将T用作方法形参的。
T BBB();
}
再定义
class DataProcessEntityDelegator<T>
{
private readonly DataProcessEntity entity;
public DataProcessEntityDelegator<out T>(A a, B b, C c)
{
entity=new DataProcessEntity(a,b,c);
}
public void AAA() =>entityAAA();
public T BBB() = > entityBBB();//注:这是C#60以后的简写语法,否则自己写完整的函数体。
}
然后你就可以快乐的在代码里写:
private static Dictionary<DataTagEnum, IDataProcessEntityDelegator<BaseQueryInfo>> DataTagEnumQueryDict = new
DataTagEnumQueryDictAdd( ,DataProcessEntityDelegator<BaseQueryInfo>{} );
DataTagEnumQueryDictAdd( ,DataProcessEntityDelegator<MultiBorrowTag>{} );
DataTagEnumQueryDictAdd( ,DataProcessEntityDelegator<BlackListTag>{} );
用哪种方法就看你的觉悟了
这个问题让我觉得有点别扭,是这样的:首先Array是非泛型类型,自然不能够完成这个任务,即使通过添加额外的限定条件也显得过于麻烦,有悖泛型的优点;既然如此就用一般的数组声明方式,只不过这种封装优点多余,比如有个类型ClassA,那么声明他的数组:ClassA[] aArray = new ClassA[5];那么,从中提取一下,写成泛型方法:public T[] getTArray<T>(int arrLength){return new T[5];}这样就可以了,参数限定了数组长度。调用的时候这样:var useResult = getTArray<ClassA>(5);就能得到相同的结果。另外值得注意的是,数组的元素都是空引用。
在c语言中方法被声明时。
在c语言中如果方法被声明也就是被定义时作为泛型类或者泛型接口的一部分,程序员就可以使用他们自己的泛型类型来替换原有的类型。
泛型的概念代表了对类型的抽象。它是一个非常强大的概念,它允许开发抽象算法和数据结构,并提供实体类型以供后续 *** 作。
C#泛型编程
泛型:通过参数化类型来实现在同一份代码上 *** 作多种数据类型。利用“参数化类型”将类型抽象化,从而实现灵活的复用。例子代码:
class Program
{
static void Main(string[] args)
{
int obj = 2;
Test<int> test = new Test<int>(obj);
ConsoleWriteLine("int:" + testobj);
string obj2 = "hello world";
Test<string> test1 = new Test<string>(obj2);
ConsoleWriteLine("String:" + test1obj);
ConsoleRead();
}
}
class Test<T>
{
public T obj;
public Test(T obj)
{
thisobj = obj;
}
}
输出结果是:
int:2
String:hello world
程序分析:
1、 Test是一个泛型类。T是要实例化的范型类型。如果T被实例化为int型,那么成员变量obj就是int型的,如果T被实例化为string型,那么obj就是string类型的。
2、 根据不同的类型,上面的程序显示出不同的值。
C#泛型特点:
1、如果实例化泛型类型的参数相同,那么JIT编辑器会重复使用该类型,因此C#的动态泛型能力避免了C++静态模板可能导致的代码膨胀的问题。
2、C#泛型类型携带有丰富的元数据,因此C#的泛型类型可以应用于强大的反射技术。
3、C#的泛型采用“基类、接口、构造器,值类型/引用类型”的约束方式来实现对类型参数的“显示约束”,提高了类型安全的同时,也丧失了C++模板基于“签名”的隐式约束所具有的高灵活性
C#泛型继承:
C#除了可以单独声明泛型类型(包括类与结构)外,也可以在基类中包含泛型类型的声明。但基类如果是泛型类,它的类型要么以实例化,要么来源于子类(同样是泛型类型)声明的类型参数,看如下类型
class C<U,V>
class D:C<string,int>
class E<U,V>:C<U,V>
class F<U,V>:C<string,int>
class G:C<U,V> //非法
E类型为C类型提供了U、V,也就是上面说的来源于子类
F类型继承于C<string,int>,个人认为可以看成F继承一个非泛型的类
G类型为非法的,因为G类型不是泛型,C是泛型,G无法给C提供泛型的实例化
泛型类型的成员:
泛型类型的成员可以使用泛型类型声明中的类型参数。但类型参数如果没有任何约束,则只能在该类型上使用从SystemObject继承的公有成员。如下图:
泛型接口:
泛型接口的类型参数要么已实例化,要么来源于实现类声明的类型参数
泛型委托:
泛型委托支持在委托返回值和参数上应用参数类型,这些参数类型同样可以附带合法的约束
delegate bool MyDelegate<T>(T value);
class MyClass
{
static bool F(int i){}
static bool G(string s){}
static void Main()
{
MyDelegate<string> p2 = G;
MyDelegate<int> p1 = new MyDelegate<int>(F);
}
}
泛型方法:
1、C#泛型机制只支持“在方法声明上包含类型参数”——即泛型方法。
2、C#泛型机制不支持在除方法外的其他成员(包括属性、事件、索引器、构造器、析构器)的声明上包含类型参数,但这些成员本身可以包含在泛型类型中,并使用泛型类型的类型参数。
3、泛型方法既可以包含在泛型类型中,也可以包含在非泛型类型中。
泛型方法声明:如下
public static int FunctionName<T>(T value){}
泛型方法的重载:
public void Function1<T>(T a);
public void Function1<U>(U a);
这样是不能构成泛型方法的重载。因为编译器无法确定泛型类型T和U是否不同,也就无法确定这两个方法是否不同
public void Function1<T>(int x);
public void Function1(int x);
这样可以构成重载
public void Function1<T>(T t) where T:A;
public void Function1<T>(T t) where T:B;
这样不能构成泛型方法的重载。因为编译器无法确定约束条件中的A和B是否不同,也就无法确定这两个方法是否不同
泛型方法重写:
在重写的过程中,抽象类中的抽象方法的约束是被默认继承的。如下:
abstract class Base
{
public abstract T F<T,U>(T t,U u) where U:T;
public abstract T G<T>(T t) where T:IComparable;
}
class MyClass:Base
{
public override X F<X,Y>(X x,Y y){}
public override T G<T>(T t) where T:IComparable{}
}
对于MyClass中两个重写的方法来说
F方法是合法的,约束被默认继承
G方法是非法的,指定任何约束都是多余的
简介什么是泛型 泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部份,那些部份在使用前必须作出指明。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型。泛型类是引用类型,是堆对象,主要是引入了类型参数这个概念。 泛型的定义 泛型的定义主要有以下两种: 在程序编码中一些包含类型参数的类型,也就是说泛型的参数只可以代表类,不能代表个别对象。(这是当今较常见的定义)在程序编码中一些包含参数的类。其参数可以代表类或对象等等。(现在人们大多把这称作模板)不论使用那个定义,泛型的参数在真正使用泛型时都必须作出指明。 一些强类型编程语言支援泛型,其主要目的是加强类型安全及减少类转换的次数,但一些支持泛型的编程语言只能达到部份目的。 [编辑本段]一些编程语言的泛型特性 NET Framework 的泛型 由于NET Framework 泛型的类型参数之实际类型在运行时均不会被消除,运行速度会因为类型转换的次数减少而加快。 另外,使用 GetType 方法可於程序运行时得知泛型及其类型参数的实际类型,更可以运用反射编程。 允许对个别泛型的类型参数进行约束,包括以下几种形式(假设 C是泛型的类型参数, 是一般类、泛类,或是泛型的类型参数):T 是一个类。T 是一个值类型。T 具有无参数的公有建构方法。T 实现接口 I 。T 是 C ,或继承自 C 。 Java 的泛型 Java 泛型的参数只可以代表类,不能代表个别对象。由于 Java 泛型的类型参数之实际类型在编译时会被消除,所以无法在运行时得知其类型参数的类型。Java 编译器在编译泛型时会自动加入类型转换的编码,故运行速度不会因为使用泛型而加快。Java 允许对个别泛型的类型参数进行约束,包括以下两种形式(假设 T 是泛型的类型参数,C 是一般类、泛类,或是泛型的类型参数):T 实现接口 I 。T 是 C ,或继承自 C 。 C++ 的泛型(模板) C++ 无法对泛型的类型参数进行约束。在编译时,每个被使用的封闭泛型类型(即是所有泛型参数的实际类型都已被指明的泛型)都会有独立的编码产生,编译器会在此时确保类型安全性。可是如果泛型要运用其泛型参数的某成员,而该泛型参数又不包含该成员的时候,编译器所产生的错误信息或会看似与实际问题无关,增加除错的难度。 [编辑本段]泛型的好处: 泛型是c#20的一个新增加的特性,它为使用c#语言编写面向对象程序增加了极大的效力和灵活性。不会强行对值类型进行装箱和拆箱,或对引用类型进行向下强制类型转换,所以性能得到提高。它允许程序员将一个实际的数据类型的规约延迟至泛型的实例被创建时才确定。泛型为开发者提供了一种高性能的编程方式,能够提高代码的重用性,并允许开发者编写非常优雅的解决方案。
以上就是关于C#类及其子类怎么作为泛型传递全部的内容,包括:C#类及其子类怎么作为泛型传递、如何根据Class类型的入参定义泛型数组并返回、c中泛型什么时候替换等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)