泛型的有余行使,NET基础之自定义泛型

本篇小说首要介绍泛型的施用。

目的与泛型

在.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.对象

宣示3个可空的int类型,由于C#语法对这些做了简化平时我们都不那样写,而是那样写:

泛型的有余行使,NET基础之自定义泛型。上面是贰个非泛型的事例
func swapTwoIntValue(a: inout Int, b: inout Int){  
    let tempValue = a  
    a = b  
    b = tempValue  
}

上面定义了三个普通类和1个泛型类,大家能够肯定看到泛型类和常见类最大的界别便是多了一个<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创设3个持续自某些(或一些)类型的匿名类的指标,如下所示:

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

目标和类一样,只可以有三个父类,但能够实现三个接口,几个超类型跟在冒号:后边用逗号,分隔。
设若只想建立两个指标,不一而再任何类,不落到实处任何接口,可以那样写:

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

运作代码,查看结果:

亚洲必赢官网 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()
    }
})

运维代码,查看结果:

亚洲必赢官网 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);

Java泛型提供了问号?通配符,上面的<? extends E>代表此办法接受 E
或许 E 的
一些子类型对象的汇集。所以能够透过addAll()方法把List<String>赋值给List<Object>。

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

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

亚洲必赢官网 3

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

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

亚洲必赢官网 4

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

比较之下上边两段代码能够旁观,用out来修饰T,只可以消费T类型,不能够回来T类型;
用in来修饰T,只可以回去T类型,不可能消费T类型。简单来讲正是 in 是消费者, out
是劳动者。

概念泛型类

2.泛型函数

但品种只可以是一个门类。 那么泛型和花色之间是何等关联呢?

2.2 类型投影

上面说到了outin修饰符,借使大家绝不他们来修饰泛型,晤面世那种状态:

class Box<T> {
}

亚洲必赢官网 5

编写翻译不经过,因为Array<T>对于类型T是不可变的,所以Box<Any>和Box<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  
}  

事实上相当粗略,泛型在概念的时候,是泛指类型;在使用的时候,就要求被钦定,到底使用哪个品种。

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能够是专断的标示符,只要服从命名规则即可。

本条事例用泛型完美的化解了上述的标题,只必要定义一个泛型函数,只要保障 传入的多少个参数是同三个品种,就毫无依照传入参数的门类分歧而写不一致的方法。

打比方,定义时,定义了1位。但在运用时,必须明显钦命,到底是黄种人依旧黄种人。

总结

本篇小说比较了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

亚洲必赢官网 6

 

3.类型参数

泛型的使用

能够把项目用在类成员的归来类型,方法参数类型等,例如:

在地点的泛型函数例子中,占位符T是项目参数的三个例子。类型参数钦点并取名一个占位符类型,并用<>包裹,放在函数名背后。一旦一个参数类型分明,就能够钦赐参数类型,只怕重返值的品类,仍可以用作函数体的表明类型。在调用的时候会被实际的门类替代,如传递的是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,只是3个描述性的名字,平时用单一的字母来定名,例如: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的用法

上面代码定义了二个Int类型的泛型Generic。

 

上面显示3个非泛型版本栈
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.恢弘2个泛型类型

无论泛型到底是String,int,bool大概是1个Class类型,都得以被机关赋值。

假借使值类型就赋值0,引用类型就赋值null。

能够扩充1个泛型类型,给这一个泛型类型添加属性、方法、下标等。
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中,能够作用任何项目。不过也能够拉长1个封锁,比如内定三个体系必须选拔某钻探也许是钦定类等。在斯威夫特中(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代表是某些类,第四个参数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 钻探的。全体的Swift标准项目暗中认可都以支撑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必须是援引类型

在概念协议的时候,有时候用三个依旧七个关系类型作为定义协议的一局地,关联类型作为协商的一片段,为有个别项目提供了七个占位符,其实际类型会在秉承的时候被钦定。并用关键字typealias 关键字来钦点关联名

以此限制正是指【where T : Base】。

                                where
T:interface                                 
钦命类型T必须贯彻是接口也许实现了接口

关系类型实践

它的限制是,供给大家钦赐的类型T必须是Base,可能该类型继承自Base,如FanXing类。

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

上边定义2个商议,协议钦命了二个关系类型
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不要看到代码多 其实很简短的
耐心看下来

由此扩张添加协商的一致性描述了什么使用一个已存在项目符合3个磋商,那包罗了动用关联协议
 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

Swift中的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类型使用。

不过,那里大家发现2个题材,那正是,在泛型函数里,使用泛型对象的时候,大家发现目的都以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  
}    

上边大家抬高中二年级个反射函数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;
    }
}

结果:

出口结果如下:

亚洲必赢官网 7

亚洲必赢官网 8

如此一个泛型就OK了。

那般我们就赢得了大家想要的结果,假如想接纳泛型类里的函数,道理也同等,只需求用反射来调用即可。

                                                         ——Stay
hungry!Stay foolish!

结语

看样子此间,有个别同学只怕会认为泛型很复杂,连使用其指标下的个性,都得反射,太烦琐了,还不及不用吧。

有如此想方设法的同班,心里斟酌就好了,倘使对老车手这样说,他必定会内心默默的微笑,然后对您说,你想的正确性。

接下来,你就不曾然后了。

泛型的使用,开篇已经说了,首要用在增进代码的可重用性、类型安全性和频率上。

万一头是概念两个类,调用一个天性,那泛型的存在就是鸡肋。

但实则,大家的种类永远只有更复杂,更复杂,更复杂。由此泛型才有了用武之地。

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

C#语法——元组类型

C#语法——await与async的正确打开药情势


注:此小说为原创,欢迎转发,请在篇章页面鲜明地方给出此文链接!
若你认为那篇作品可以接受,请点击下右下角的【推荐】,卓殊谢谢!

网站地图xml地图