本篇文章重要介绍泛型的施用。

目的与泛型

在.NET中泛型使用十二分频繁,在控制台应用程序中,暗许的引入了System.Collection.Generics名称空间,个中就提供了大家通常选择的泛型:List<T>和Dictionary<T>,相信用过它们的都理解它们的强有力。还有一种我们日常使用的简约的泛型:System.Nullable<T>,即可空类型。大家能够:

泛型可以让开发者编写自定义供给已经肆意档次的灵活可用的的函数和花色。能够让我们防止再度的代码。用一种清晰和浮泛的办法来发挥代码的打算。

泛型是.NET Framework 2.0
版类库就曾经提供的语法,主要用以抓实代码的可重用性、类型安全性和功能。

目录

  • 1.对象
    1.1 匿名类与对象
    1.2 静态类成员与伴生对象
  • 2.泛型
    2.1 型变
    2.2 类型投影
    2.3 泛型函数
    2.4 泛型约束

System.Nullable<int> nullableInt;

1.泛型化解的难点

泛型的概念

1.对象

声惠氏(WYETH)个可空的int类型,由于C#语法对这些做了简化常常我们都不这么写,而是那样写:

下边是三个非泛型的事例
func swapTwoIntValue(a: inout Int, b: inout Int){  
    let tempValue = a  
    a = b  
    b = tempValue  
}

下边定义了一个普通类和3个泛型类,我们得以显然看到泛型类和经常类最大的界别就是多了一个<T>。

1.1 匿名类与对象表明式

Java中有匿名类那些概念,指的是在创立类时无需钦赐类的名字。在Kotlin中也有机能相似的“匿名类”,叫做对象,举个例子:

Java匿名类

public class Login {

    private String userName;

    public Login(String userName) {
        this.userName = userName;
    }

    public void printlnUserName() {
        System.out.println(userName);
    }
}

public class JavaActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        printlnUserName(new Login("Czh") {
            @Override
            public void printlnUserName() {
                super.printlnUserName();
            }
        });
    }

    public void printlnUserName(Login login) {
        login.printlnUserName();
    }
}

Kotlin完结地点的代码,要用关键字object创设多个延续自有个别(或一些)类型的匿名类的靶子,如下所示:

class KotlinActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //object是一个对象,该对象继承自上面的Login
        printlnUserName(object : Login("Czh") {
            override fun printlnUserName() {
            }    
        })
    }

    fun printlnUserName(login: Login) {
        login.printlnUserName()
    }
}

对象object还足以兑现接口,如下所示:

//View.OnClickListener是一个interface
button.setOnClickListener(object : View.OnClickListener {
    override fun onClick(v: View?) {
    }
})

对象和类一样,只可以有1个父类,但足以兑现七个接口,七个超类型跟在冒号:后边用逗号,分隔。
万三只想建立3个目的,不三番五次任何类,不落到实处别的接口,能够如此写:

fun foo(){
    val abc = object {
            var a = 1
            var b = 2
    }
    Toast.makeText(this, "${abc.a}${abc.b}", Toast.LENGTH_SHORT).show()
}

运作代码,查看结果:

金沙注册送58 1

请留意,匿名对象能够用作只在地头和村办功效域中宣示的项目。如果您选择匿名对象作为国有函数的归来类型或许当作公有属性的花色,那么该函数或性质的实际类型会是匿名对象注解的超类型,假设您没有评释任李光类型,就会是
Any。在匿名对象中增长的积极分子将不可能访问。如下所示:

class User {
    // 私有函数,所以其返回类型是匿名对象类型
    private fun getUserName() = object {
        val userName = "Czh"
    }

    // 公有函数,所以其返回类型是 Any
    fun getAge() = object {
        val age = 22
    }

    fun get() {
        getUserName().userName
        //getAge().age //编译错误
    }
}
  • 里头类访问成效域内的变量

就好像 Java
匿名内部类一样,Java能够用final表明变量,使匿名内部类能够行使来源包蕴它的功能域的变量。如下所示:

final int age = 22;
printlnUserName(new Login() {
    @Override
    public void printlnUserName() {
        //因为age用final声明,所以不能修改
        if (age == 22){
            return;
        }
  }
});

而Kotlin在匿名对象中能够专擅拜访或修改变量age,如下所示:

var age = 22
printlnUserName(object : Login() {
    override fun printlnUserName() {
        age = 23
        Toast.makeText(this@MainActivity, "$age", Toast.LENGTH_SHORT).show()
    }
})

运作代码,查看结果:

金沙注册送58 2

int? nullableInt
本条函数用来交流八个整形的数值
var a = 1  
var b = 2  
swapTwoIntValue(a: &a, b: &b)  
print(a, b)//2,1 

所以,那一个<T>就标志了,这些类是泛型类。在那之中那些T,也得以写成A,B,C,D或任何字符。

1.2 伴生对象

Java中有静态类成员,而Kotlin中没有,要贯彻像静态类成员的功用,就要采纳伴生对象。

Java静态成员:

class User {
    static User instance = new User();

    public void printlnUser() {
    }
}
//调用
User.instance.printlnUser()

Kotlin类内部的指标注明可以用 companion 关键字标记:

class User {
    companion object {
        var instance = User()
    }

    fun printlnUser() {
    }
}
//调用
User.instance.printlnUser()

下边重点介绍一下如何自定义泛型。

对此那些事例,假若大家想换换五个Double类型、恐怕是其他类其他值,就必要针对各种项目写分歧的点子,只是参数类型分化。为了消除那些标题,Swift提供了泛型,帮助大家来缓解那个题材。
public class Generic
{
    public String Name;
}

public class Generic<T>
{
    public T Name;
}

泛型

 

留意:斯威夫特是平安的语言,不容许三个例外门类调换值

泛型,顾名思义,正是泛指的项目。好比相公,女孩子,黄种人,黄种人,能够泛称为【人】。

2.1型变

Java泛型

public class Box<T> {
    public T value;

    public Food(T t) {
        value = t;
    }
}

new Box<String>("123");
new Box<Integer>(1);

对应的Kotlin泛型

class Box<T>(t: T) {
    var value = t
}
var box: Box<String> = Box("123")
var box2: Box<Int> = Box(123)

能够看看Java跟Kotlin定义泛型的不二法门都以大半的,分裂的是Java中的泛型有通配符,而Kotlin没有。举个例子:

List<String> strings = new ArrayList<String>();
List<Object> objects = strings;//编译错误

Java编写翻译器不以为List<String>是List<Object>的子类,所以编写翻译不通过。那我们换种写法:

List<String> strings = new ArrayList<String>();
List<Object> objects = new ArrayList<Object>();
objects.addAll(strings);//编译通过

为何调用addAll()方法就能编写翻译通过呢,看一下他的源码:

boolean addAll(Collection<? extends E> c);

泛型的有余使用,NET基础之自定义泛型。Java泛型提供了问号?通配符,下边包车型客车<? extends E>代表此办法接受 E
可能 E 的
一些子类型对象的聚集。所以可以因而addAll()方法把List<String>赋值给List<Object>。

Kotlin的泛型没有提供通配符,取而代之的是outin修饰符。先举个例证:

//用out修饰T
class Box<out T> {
}

金沙注册送58 3

(淡玉绿波浪线标记处为编写翻译错误)

//用in修饰T
class Box<in T> {
}

金沙注册送58 4

(水绿波浪线标记处为编写翻译错误)

对照上边两段代码能够观看,用out来修饰T,只好消费T类型,不可能回去T类型;
用in来修饰T,只可以回到T类型,无法消费T类型。不难的话正是 in 是主顾, out
是劳动者。

概念泛型类

2.泛型函数

但项目只可以是贰个档次。 那么泛型和项目之间是什么样关系呢?

2.2 类型投影

地点说到了outin修饰符,若是大家毫不他们来修饰泛型,会出现那种情景:

class Box<T> {
}

金沙注册送58 5

编写翻译不通过,因为Array<T>对于类型T是不可变的,所以Box<Any>和博克斯<String>何人也不是哪个人的子类型,所以编写翻译不经过。对于那种状态,我们还能用outin修饰符来化解,但不是用来修饰Box<T>,如下所示:

fun test(strs: Box<Any>) {
    var objects: Box<in String> = strs
    //编译通过
}

fun test2(strs: Box<String>) {
    var objects: Box<out Any> = strs
    //编译通过
}

位置的缓解方法叫做类型投影,Box<out Any>也正是 Java 的 Box<?
extends Object>、Box<in String>相当于 Java 的 Box<? super
Object>。

开创泛型类是需求在类定义中用尖括号语法:

下边是多少个泛型的函数
func swapTwoValue<T>(a: inout T, b: inout T){  
    let tempValue = a  
    a = b  
    b = tempValue  
}  

金沙注册送58,其实很不难,泛型在概念的时候,是泛指类型;在利用的时候,就供给被钦定,到底使用哪个品种。

2.3 泛型函数

不单类能够有档次参数。函数也能够有。类型参数要放在函数名称以前:

fun <T> singletonList(item: T): List<T> {
    // ……
}

//调用
val l = singletonList<Int>(1)
singletonList(l)

接近于Java的泛型方法:

public <T> T singletonList(T item) {
    // ……
}

//调用
singletonList(1);
class MyGenericClass<T>
{
    ...
}
以此函数主体、功能跟下面的例子类似,用来交换五个一律类型的值,不过这几个函数用 T 占位符来替代实际的品种。并不曾点名具体的花色,不过传入的a ,b 必须是同一类型T。在调用那么些函数的时候才能钦点 T 是那种具体的种类。还有函数名后跟的百般 <T> 是函数定义的叁个占位类型名,并不会查找T的具体项目
swapTwoValue(&oneInt, b: &twoInt)  
print("oneInt:\(oneInt),twoInt:\(twoInt)") // oneInt:3,twoInt:4  

var oneStr = "hello"  
var twoStr = "world"  

swapTwoValue(&oneStr, b: &twoStr)  
print("oneStr:\(oneStr),twoStr:\(twoStr)")// oneStr:world,twoStr:hello  

var oneDouble = 10.01  
var twoDouble = 20.02  
swapTwoValue(&oneDouble, b: &twoDouble)  
print("oneDouble:\(oneDouble),twoDouble:\(twoDouble)")// oneDouble:20.02,twoDouble:10.01    

即,使用时,就不在是泛指类型,而是一定项目。

2.4 泛型约束

泛型约束能够范围泛型参数允许行使的项目,如下所示:

Kotlin代码

fun <T : Comparable<T>> sort(list: List<T>) {
}

sort(1) //编译错误
sort(listOf(1)) //编译通过

上述代码把泛型参数允许利用的体系限制为 List<T>

Java中也有相近的泛型约束,对应的代码如下:

public static <T extends Comparable> List<T> sort(List<T> list){
}

若是没有点名泛型约束,Kotlin的泛型参数默许类型上界是Any,Java的泛型参数默许类型上界是Object


T能够是自由的标示符,只要服从命名规则即可。

其一例子用泛型完美的消除了上述的标题,只要求定义二个泛型函数,只要保障 传入的多个参数是同贰个门类,就毫无依照传入参数的连串不一致而写差别的章程。

比喻,定义时,定义了一人。但在采纳时,必须鲜明钦赐,到底是白人依然白种人。

总结

本篇文章相比了Java匿名类、静态类与Kotlin对象的写法和三种语言中对泛型的利用。相对来说,Kotlin还是在Java的基本功上作了有个别更上一层楼,扩张了有个别语法糖,更灵活也更安全。

参考文献:
Kotlin语言粤语站、《Kotlin程序开发入门精要》

引进阅读:
从Java到Kotlin(一)为啥使用Kotlin
从Java到Kotlin(二)基本语法
从Java到Kotlin(三)类和接口
从Java到Kotlin(五)函数与Lambda表达式
从Java到Kotlin(六)扩大与寄托
从Java到Kotlin(七)反射和注释
从Java到Kotlin(八)Kotlin的任何技术
Kotlin学习材料集聚


越来越多精粹文章请扫描下方二维码关切微信公众号”AndroidCzh“:那里将长久为您分享原创小说、Android开发经历等!
QQ交流群: 705929135

金沙注册送58 6

 

3.类型参数

泛型的选用

能够把品种用在类成员的回来类型,方法参数类型等,例如:

在上面包车型大巴泛型函数例子中,占位符T是连串参数的一个事例。类型参数钦点并取名2个占位符类型,并用<>包裹,放在函数名背后。一旦三个参数类型分明,就能够钦定参数类型,或然再次来到值的品种,还可以用作函数体的诠释类型。在调用的时候会被实际的种类替代,如传递的是Int,就替换为Int,借使传入的是Double类型就替换为Double等等

泛型类跟普通类的应用方法相同,都急需实例化对象,再由对象来调用内部的性质或措施。

class MyGenericClass<T1, T2, T3>
{
    private T1 t1Object;

    public MyGenericClass(T1 item)
    {
        t1Object = item;
    }

    public T1 T1Object
    {
        get
        {
            return t1Object;
        }
    }
}

4.命名类型参数

上面代码实例化了泛型Generic,实例化时,还点名了该泛型Generic的内定项目为String。

只顾倘使不可能假定提供了何等品种。上边包车型地铁代码不可能履行:

上边包车型大巴泛型例子的 T,只是贰个描述性的名字,常常用单一的假名来命名,例如:T、U、V等。T代表只是一个占位符,命名规则同驼峰命名法

为此要给泛型Generic的属性Name赋值,就须求赋值字符串类型的值。

class MyGenericClass<T1, T2, T3>
{
    private T1 t1Object;

    public MyGenericClass()
    {
        t1Object = new T1();
    }
}

5.泛型类型

public static void Excute()
{
    Generic<String> gs = new Generic<String>();
    gs.Name = "Kiba518";
}

因为大家不通晓T1是或不是有国有的默许构造函数。

除外定义泛型函数,还是能够定义泛型类型。如Array,Dictionary的用法

上边代码定义了1个Int类型的泛型Generic。

 

上边展现一个非泛型版本栈
struct IntStack {  
    var items = [Int]()  
    mutating func push(item: Int) {  
        items.append(item)  
    }  
    mutating func pop(item: Int) -> Int {  
        return items.removeLast()  
    }  
} 
public static void Excute()
{
    Generic<int> gs = new Generic<int>();
    gs.Name = 518;
}

default关键字

其一是贰个泛型版本的栈
struct Stack<T> {  
    var items = [T]()  
    mutating func push(item: T) {  
        items.append(item)  
    }  
    mutating func pop(item: T) -> T {  
        return items.removeLast()  
    }  
} 

泛型的默许值

假定我们定义了多少个泛型的字段,大家想在构造函数中早先化它,不过我们不了解它的引用类型或许值类型,那么default就派上用场了:

率先在函数名背后加<泛型类型名>,<>里面注解项目参数名。然后在函数主体里面实现跟非泛型栈类似的作用。那样这些泛型结构体就不只好压栈Int类型的值,还足以是任何项目
var stack = Stack<String>() //要在类型名后面加<类型名>  
stack.push("uno")  
stack.push("dos")  
stack.push("tres")  
stack.push("cuatro")  

print(stack.pop()) // cuatro  

泛型的私下认可值,如上面代码所示。须求使用default(T)来赋值。

public MyGenericClass()
{
    t1Object = default(T1);
}

6.增添二个泛型类型

任由泛型到底是String,int,bool恐怕是2个Class类型,都能够被自动赋值。

若果是值类型就赋值0,引用类型就赋值null。

能够增加二个泛型类型,给这几个泛型类型添加属性、方法、下标等。
extension Stack{  
    //给泛型Stack扩展一个计算型属性topItem,返回最上面的item  
    var topItem: T? {  
        return items.isEmpty ? nil : items[items.count-1]  
    }  
} 
public static void Excute()
{
    Generic<int> gs = new Generic<int>();
    gs.Name = 518;
    Generic<Task> gsTask = new Generic<Task>();
    gsTask.Name = new Task(()=> {
        Console.WriteLine("Kiba518");
    });
}

public class Generic<T>
{
    public T Name = default(T); 
}

 

7.类型约束

泛型的自律

封锁类型

在上头的SwapTwoVlues 和 Stack中,能够功用任何项目。但是也能够增加一个羁绊,比如钦定三个档次必须接纳某商谈恐怕是钦定类等。在斯维夫特中(Bool,Int,Doube,String暗中认可都以哈希的),Dictionary的键就须求必须是可哈希的,方便字典查找是不是已盈盈某些键的值。

在泛型类中,有个专门的牢笼可供大家运用。

在概念泛型的时候我们能够对项目举办约束,通过where关键字贯彻:

花色约束语法

当大家不出示的宣示时,这几个约束不设有。但当大家来得的扬言的时候,那些约束就会履行。

class MyGenericClass<T1> where T : constraint1,constraint
{
    ...
}
能够在项目参数名背后加三个体系或许协议名,通过冒号隔开,八个类型参数之间用逗号隔断
func somFuntion<C:NSObject, P: NSObjectProtocol>(someClass: C, someProtocol: P){  
    //这里用NSObject和NSObjectProtocol做例子  
} 

上边,大家来看看这些专门的牢笼。

constraint定义了封锁,八个约束用逗号隔离,假如有多少个类型:

在概念的那些函数中,有四个连串约束,第一次品种参数C代表是某些类,第3个参数P代表有个别体协会议。
public static void Excute()
{ 
    Generic<FanXing> gFanXing = new Generic<FanXing>();
    Generic<Base> gFanXingBase = new Generic<Base>();
    //Generic<string> gs = new Generic<string>(); 这样定义会报错
} 
public class Generic<T> where T : Base
{
    public T Name = default(T); 
} 
public class Base  
{
    public string Name { get; set; }
}
public class FanXing : Base
{
    public new string Name { get; set; }
}
class MyGenericClass<T1, T2> where T1 : constraint1 where T2 : constraint
{
    ...
}

品种约束实践

如上边代码所示,【where T : Base】正是其一更加的羁绊。

上边给出一些可用的自律

其一非泛型类型的点子用来查找有些字符串是还是不是在字符数组中,存在重返index
func findStrInArray(_ array: [String], strToFind: String) -> Int?{  
    for (index,value) in array.enumerated(){  
        if strToFind == value{  
            return index  
        }  
    }  
    return nil  
}

下边那是对准地点非泛型方法泛型版本的艺术

func findIndex<T: Equatable> (_ array: [T], _ valueToFind: T) -> Int? {  
    for  (index,value) in array.enumerated(){  
        if value == valueToFind { //如果没指定S:Equatable 这句话会编译不通过  
            return index  
        }  
    }  
    return nil  
} 

当展现注脚那些约束的时候,定义会限制泛型的品种。

                                       
约束                                                                 
说明

在这几个泛型例子中,不是具有的品类都能够 用 == 来相比较的,全部必须内定泛型类型参数的封锁为 斯维夫特提供的 Equatable 协议,那代表T代表的项目必须是辅助 Equatable 切磋的。全数的斯威夫特标准项目暗中同意都以支撑Equatable商讨的.
let value = findIndex([3.14159, 0.1, 0.25], 9.3)  
// doubleIndex 类型为 Int?,其值为 nil,因为 9.3 不在数组中  
let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")  
// stringIndex 类型为 Int?,其值为 2  

什么是限量泛型的品类呢?

                                where
T:struct                                    
使用结构约束,类型T必须是值类型

8.关联类型

相当的粗略,泛型T,是泛指某二个档次。大家在概念泛型类时,还需出示的钦命项目,此时大家呈现钦定的档次,要受这一个界定。

                                where
T:calss                                      
类约束钦命,类型T必须是援引类型

在概念协议的时候,有时候用1个依旧七个事关类型作为定义协议的一有的,关联类型作为商业事务的一有的,为有个别项目提供了多少个占位符,其实际类型会在秉承的时候被内定。并用关键字typealias 关键字来内定关联合署名

其一范围就是指【where T : Base】。

                                where
T:interface                                 
钦定类型T必须完成是接口可能实现了接口

事关类型实践

它的界定是,须求大家钦命的类型T必须是Base,也许该项目继承自Base,如FanXing类。

                                where
T:base-class                              
钦定类型T必须是基类或许派生于基类

上边定义一个商议,协议钦定了二个关系类型
protocol Container{  
    associatedtype itemType //声明一个关联类型  
    mutating func appended(item: itemType)  
    var count: Int{ get }  
    subscript(i: Int) -> itemType { get }  
}

泛型的函数

                               where
T:new()                                      
内定类型T必须有3个私下认可构造函数

上面是非泛型的本子选拔 Container 协议
struct intStack: Container {  
    // IntStack 的原始实现部分  
    var items = [Int]()  
    mutating func push(item: Int) {  
        items.append(item)  
    }  
    mutating func pop() -> Int {  
        return items.removeLast()  
    }  
    //这里没设置关联类型的原因是根本不需要设置,因为很确定只返回Int型,当然你设置了也没问题。  
    // Container 协议的实现部分  
    mutating func appended(item: Int) {  
        self.push(item: item)  
    }  
    var count: Int {  
        return items.count  
    }  
    subscript(i: Int) -> Int {  
        return items[i]  
    }  
}

下边是2个泛型版本的

struct genericStack<T>: Container{  
    // genericStack<T> 的原始实现部分  
    var items = [T]()  
    mutating func push(item: T) {  
        items.append(item)  
    }  
    mutating func pop() -> T {  
        return items.removeLast()  
    }  

    //这是设置关联类型具体是什么类型  
    typealias itemType = T  

    // Container 协议的实现部分  
    mutating func appended(item: T) {  
        self.push(item: item)  
    }  
    var count: Int {  
        return items.count  
    }  
    subscript(i: Int) -> T {  
        return items[i]  
    }  
} 

在C#中,泛型不仅能够用来类,还是能够直接用于函数。

 

经过扩展多个留存项目来钦命关联类型

实际使用办法如下:

下边结合以上文化给个实例:(PS不要看到代码多 其实很简短的
耐心看下去

经过扩张添加商讨的一致性描述了哪些利用一个已存在项目符合1个商议,那包蕴了使用关联协议
 public static void Excute()
 {
     GenericFunc gf = new GenericFunc();
     gf.FanXingFunc<FanXing>(new FanXing() { Name="Kiba518"});
 }
 public class GenericFunc
 {
     public void FanXingFunc<T>(T obj)
     {
         Console.WriteLine(obj.GetType());
     }
 }

先定义八个类Animal、Cow 、Chicken和SuperCow

斯维夫特中的Array都满意了Container协议的必要,意味着能够扩张Array选拔Container协议,你能够经过三个空扩大来贯彻那一点.
extension Array :Container{  
    mutating internal func appended(item: Element) {}  
}

非常粗略,调用泛型函数的时候,内定泛型函数的[点名项目]即可。

#region Animal 虚基类 有一个name属性 Feed方法和一个虚方法MakeANoise
    //虚基类 有一个name属性 Feed方法和一个虚方法MakeANoise
    public abstract class Animal
    {
        protected string name;

        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }

        public Animal()
        {
            name = "The animal with no name";
        }

        public Animal(string newName)
        {
            name = newName;
        }

        public void Feed()
        {
            Console.WriteLine("{0} has been fed.", name);
        }

        public abstract void MakeANoise();
    }
    #endregion

//Cow Animal的子类,实现虚方法
    public class Cow:Animal
    {
        public Cow(string name) :
            base(name)
        {
        }
        public override void MakeANoise()
        {
            Console.WriteLine("{0} says 'moo!'", name);
        }
    }

//Chicken类,Animal子类
    public class Chicken:Animal
    {
        public Chicken(string name)
            : base(name)
        { }
        public override void MakeANoise()
        {
            Console.WriteLine("{0} says 'cluck'", name);
        }
    }

//Cow的子类,有一个自己的方法Fly
    class SuperCow : Cow
    {
        public SuperCow(string name) : base(name) 
        {
        }

        public void Fly()
        {
            Console.WriteLine("{0} is flying!", name);
        }

        public override void MakeANoise()
        {
            Console.WriteLine("{0} says 'I am supercow!'", name);
        }

    }
概念那一个增加之后,能够用Array当做Container类型使用。

只是,那里我们发现3个题材,那正是,在泛型函数里,使用泛型对象的时候,大家发现目的都以object类型的。

类准备好了今后,大家能够开头定义咱们的泛型了:

9.Where子句

那我们假使想使用泛型对象里的习性和办法时,要怎么做呢?

//继承了迭代器接口,这样方便使用Foreach 约束它的类型为Animal及其子类
    public class Farm<T>:IEnumerable<T> where T : Animal
    {
        private List<T> animals = new List<T>();

        public List<T> Animals
        {
            get 
            {
                return animals;    
            }
        }
        //迭代器
        public IEnumerator<T> GetEnumerator()
        {
            return animals.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return animals.GetEnumerator();
        }

        //执行所有animal的MakeANoise()
        public void MakeNoises()
        {
            foreach (T animal in animals)
            {
                animal.MakeANoise();
            }
        }
        //执行所有animal的Feed()
        public void FeedTheAnimals()
        {
            foreach (T animal in animals)
            {
                animal.Feed();
            }
        }
        //获得animals中的cow
        public Farm<Cow> GetCows()
        {
            Farm<Cow> cowFarm = new Farm<Cow>();
            foreach (T animal in animals)
            {
                if (animal is Cow)
                {
                    cowFarm.Animals.Add(animal as Cow);
                }
            }
            return cowFarm;
        }
    }
花色约束能够让我们为泛型类型充足一些羁绊和条件。为关联类型丰硕一些封锁也是很有要求的。能够在参数列表中央银行使where子句来为涉及类型丰裕约束。

也很简短,反射就足以了。

泛型定义好了,我们用写代码来调用它:

上边包车型大巴例子判断七个采用Container协议的档次是还是不是富有的成分顺序及值都相等。
func allItemsMatch<C1: Container,C2: Container>(someContainer: C1,_ anotherContainer: C2) -> Bool where C1.itemType == C2.itemType, C1.itemType: Equatable {  
    if someContainer.count != anotherContainer.count {  
        return false  
    }  
    for i in 0...someContainer.count-1{  
        if someContainer[i] != anotherContainer[i]{  
            return false  
        }  
    }  
    return true  
}    

上面大家抬高3个反射函数GetPropertyValue,专门用来取得属性。

class Program
    {
        static void Main(string[] args)
        {
            Farm<Animal> farm = new Farm<Animal>();
            farm.Animals.Add(new Cow("Jack"));
            farm.Animals.Add(new Chicken("Vera"));
            farm.Animals.Add(new Chicken("Sally"));
            farm.Animals.Add(new SuperCow("Kevin"));
            farm.MakeNoises();

            Farm<Cow> dairyFarm = farm.GetCows();
            dairyFarm.FeedTheAnimals();

            foreach (Cow cow in dairyFarm)
            {
                if (cow is SuperCow)
                {
                    (cow as SuperCow).Fly();
                }
            }
            Console.ReadKey();
        }
    }
其一泛型函数在项目参数里面添加了where子句约束,C1,C2都不能够不是选取Container协议的体系,并且C一 、C2的泛型类型必须一致,而且C1的泛型类型必须是选拔Equatable的。
var stackOfStrings = genericStack<String>()  
stackOfStrings.appended(item: "uno")  
stackOfStrings.appended(item: "dos")  
stackOfStrings.appended(item: "tres")  

var arrayOfStrings = ["uno", "dos", "tres"] //array类型的满足Container类型,参考上面的extension Array  

if allItemsMatch(stackOfStrings, arrayOfStrings) {  
    print("All items match.")  
} else {  
    print("Not all items match.")  
}  
//结果是:All items match. 
public class GenericFunc
{
    public void FanXingFunc<T>(T obj)
    { 
        var name = GetPropertyValue(obj, "Name");
        Console.WriteLine(name); 
    }
    public object GetPropertyValue(object obj, string name)
    {
        object drv1 = obj.GetType().GetProperty(name).GetValue(obj, null);
        return drv1;
    }
}

结果:

输出结果如下:

金沙注册送58 7

金沙注册送58 8

那般一个泛型就OK了。

如此我们就拿走了小编们想要的结果,倘若想利用泛型类里的函数,道理也一样,只供给用反射来调用即可。

                                                         ——Stay
hungry!Stay foolish!

结语

看看此间,有些同学恐怕会以为泛型很复杂,连使用其指标下的属性,都得反射,太繁琐了,还不及不用吧。

有诸如此类想方设法的同学,心里研商就好了,假使对老驾乘员那样说,他自然会内心默默的微笑,然后对你说,你想的不易。

然后,你就没有然后了。

泛型的应用,开篇已经说了,首要用在增长代码的可重用性、类型安全性和功能上。

万2头是概念贰个类,调用2个属性,那泛型的留存正是鸡肋。

但实在,大家的系统永远只有更扑朔迷离,更扑朔迷离,更扑朔迷离。因而泛型才有了用武之地。

C#语法——委托,架构的血流

C#语法——元组类型

C#语法——await与async的不错打开药格局


注:此小说为原创,欢迎转发,请在文章页面明显地方给出此文链接!
若你认为那篇小说还不易,请点击下右下角的【推荐】,格外多谢!

相关文章

网站地图xml地图