Net is as typeof 运行运算符详解 net 自定义泛型那点事
Net is as typeof 运行运算符详解
概述
在了解运行运算符的前提我们需要了解什么是RTTI ,在任何一门面向对象的语言中,都有RTTI这个概念(即 运行时)。
RTTI(Run-Time Type Identification),通过运行时类型信息程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型。
运行时类型标识
运行时标识有什么用呢?
- IS运算符
class Program { static void Main(string[] args) { People p1 = new People(); Person p2 = new Person(); if (p1 is People) { Console.WriteLine("p1 是 People 的对象 ~~~"); } if (p2 is People) { //这个打印,因为p2是Person类型的对象,而Person类型派生于People类型 //由于Person对象可以转换为People类型,因此Person对象与People类型是兼容的,但是反过来就不成立 Console.WriteLine("p2 是 People 的对象..."); } if (p1 is Person) { Console.WriteLine("p1 是 Person 的对象***"); } if (p2 is Person) { Console.WriteLine("p2 是 Person 的对象---"); } if (p1 is object) { Console.WriteLine("任何类的父类为object"); } Console.Read(); } } /// <summary> /// 个人信息 /// </summary> public class People { public string Name { get; set; } public int Age { get; set; } public string Sex { get; set; } } /// <summary> /// 人的群体信息 /// </summary> public class Person: People { public string Household { get; set; } }
as运算符:
在运行期间执行类型转换,并且能够使得类型转换失败不抛异常,而返回一个null值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
using System; using System.Collections.Generic; using System.Data; namespace testData { class Program { static void Main( string [] args) { People p1 = new People() { Age=30,Sex= "女" ,Name= "mainaizi" }; Person p2 = new Person() { Age=29,Sex= "男" ,Name= "大棒槌" ,Household= "北京昌平" }; Person p = p1 as Person; //as类型先检查强制类型转换的有效性,如果有效,则执行强类型转换过程。这些都在这一句完成。 Console.WriteLine(p); Console.WriteLine( "清输入任意字符按Enter继续..." ); string s= Console.ReadLine(); try { Person person = (Person)p1; } catch (Exception exe) { Console.WriteLine(exe.Message); } People people = p2; Console.WriteLine(people); //这里执行的是自动转换 所以不需要强制类型转换,我们大类型转换小类型的转换叫做自动转换 Console.Read(); } } public class PersonAnws { /// <summary> /// 自定义隐士转换 /// </summary> /// <param name="v">被转化类型</param> public static implicit operator PersonAnws(People v) { People p = new People(); return p; } /// <summary> /// 自定义显示转换【这里不过多解释】 /// </summary> /// <param name="v"></param> public static explicit operator Int32(PersonAnws p) { return 0; } } /// <summary> /// 个人信息 /// </summary> public class People { public string Name { get ; set ; } public int Age { get ; set ; } public string Sex { get ; set ; } public override string ToString() { return "{" +$ "name:{this.Name},age:{this.Age},sex{this.Sex}" + "}" ; } } /// <summary> /// 人的群体信息 /// </summary> public class Person: People { public string Household { get ; set ; } public override string ToString() { return "{" + $ "name:{base.Name},age:{base.Age},sex{base.Sex},Household:{this.Household}" + "}" ; } } } |
typeof运算符:
as ,is 能够测试两种类型的兼容性。但大多数情况下,还需要获得某个类型的具体信息。这就用到了typeof,它可以返回与具体类型相关的System.Type对象,通过System.Type对象可以去顶此类型的特征。一旦获得给定类型的Type对象,就可以通过使用该对象定义的各种属性,字段,方法来获取类型的具体信息。Type类包含了很多成员,我们一起来看下吧。
using System; using System.Collections.Generic; using System.Data; namespace testData { class Program { static void Main(string[] args) { Type type= typeof(Person); Console.WriteLine(type); Console.WriteLine(type.FullName);//完整名称 Console.WriteLine(type.Name);//类名称 Console.WriteLine(type.BaseType);//基类 Console.WriteLine(type.IsSealed);//是否为密封类 Console.WriteLine(type.IsPublic);//是否是共有的 Console.Read(); } } /// <summary> /// 个人信息 /// </summary> public class People { public string Name { get; set; } public int Age { get; set; } public string Sex { get; set; } public override string ToString() { return "{"+$"name:{this.Name},age:{this.Age},sex{this.Sex}"+"}"; } } /// <summary> /// 人的群体信息 /// </summary> public class Person: People { public string Household { get; set; } public override string ToString() { return "{" + $"name:{base.Name},age:{base.Age},sex{base.Sex},Household:{this.Household}" + "}"; } } }
说到typeOf我们不得不说下类型的装载
列如
Type er= Type.GetType("System.String");
Console.WriteLine(er.Name);
我们管这种的获取类的类型叫做配件的装载。配件装载只能在本程序集中进行搜索,也就是说,在本程序集的命名空间下进行搜索。
net 自定义泛型那点事
泛型概述
泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须作出指明。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型。泛型类是引用类型,是堆对象,主要是引入了类型参数这个概念。
泛型定义
正文
假如我想输出double ,int 和 dateTime类型的类型名字和他们的值。现在需要定义方法如下
using System; using System.Data; namespace testData { class Program { static void Main(string[] args) { ShowInt(2); ShowDateTime(DateTime.Now); ShowDouble(2.52); Console.Read(); } public static void ShowInt(int value) { Console.WriteLine($"typeName:{value.GetType().Name},Value:{value}"); } public static void ShowDouble(double value) { Console.WriteLine($"typeName:{value.GetType().Name},Value:{value}"); } public static void ShowDateTime(DateTime value) { Console.WriteLine($"typeName:{value.GetType().Name},Value:{value}"); } } }
这样写起来,好像比较麻烦,我们可不可以用一个方法来代替呢???
我们很多初学者都接触过这两个泛型,
List<int> list = new List<int>();
Dictionary<int, string> dic = new Dictionary<int, string>();
第一个是列表,第二个我们称为字典,那么我们可不可以自己定义一个泛型方法呢????
泛型的语法结构及定义
泛型语法: 泛型类或方法的后面 “<T>” T 是占位符,可以是任意字母,主要代表一个类型,如果是方法,参数就应当为占位符参数。 如 Show<T>(T t);方法,User<T> 类 。
泛型的特点:1.延迟声明,2使用的时候在声明
1.泛型方法的定义和使用
using System; using System.Collections.Generic; using System.Data; namespace testData { class Program { static void Main(string[] args) { Show<int>(1); Show<double>(1.904); Show<DateTime>(DateTime.Now); Show<string>("wbc"); Console.Read(); } public static void Show<T>(T t) { Console.WriteLine($"typeName:{t.GetType().Name},Value:{t}"); } } }
我们会发现,完全可以运行,一个方法就搞定.那么我们可不可以省略 <int> ,答案是肯定的,当没有涉及到装箱拆箱操作的时候,我们完全可以省略,如下
using System; using System.Collections.Generic; using System.Data; namespace testData { class Program { static void Main(string[] args) { Show(1); Show (1.904); Show(DateTime.Now); Show("wbc"); User u = new User(); Show(u); Console.Read(); } public class User { } public static void Show<T>(T t) { Console.WriteLine($"typeName:{t.GetType().Name},Value:{t}"); } } }
有人会说了,我使用Object 作为参数,一样可以实现,为什么不使用object呢,一切类型的父类是object ,应当可以的啊??,答案是肯定的,也是可以的,知所以不使用,是因为使用object类型的时候,会产生装箱拆箱操作,这个操作会损失精度。
2泛型类的定义和使用
泛型类的语法和泛型方法的语法很像,只是关键字是class ,如 Public Class MyGer<T>{
}
那么我们来看下泛型类的使用,看如下案列:
using System; using System.Collections.Generic; using System.Data; namespace testData { class Program { static void Main(string[] args) { Person p = new Person() { Name="zhangsan",Age=28,Id=1,Id_No="110000198212193145",Address="beijiang",Sex="女" }; MyGrenric<Person> gren = new MyGrenric<Person>(); gren.Show(p); Console.Read(); } } /// <summary> /// 人的父类 /// </summary> public class BasePopleModel { public string Name { get; set; } public int Age { get; set; } public string Address { get; set; } public string Id_No { get; set; } public string Sex { get; set; } } public class Pople { public string Name { get; set; } public int Age { get; set; } public string Address { get; set; } public string Id_No { get; set; } public string Sex { get; set; } public override string ToString() { string result = "{"+$"name:{this.Name},age : {this.Age},sex : {this.Sex},no : {this.Id_No} "+"}"; return base.ToString(); } } //人的信息 public class Person : BasePopleModel { public int Id { get; set; } public override string ToString() { string result = "{ "+ $"name : {base.Name},age : {base.Age},sex : {base.Sex},no : {base.Id_No} , id : {this.Id}"+" }"; return result; } } public class MyGrenric<T> { public void Show(T t) { Console.WriteLine(t); } } }
看了上面的代码,我们可以看出,泛型类里面的方法,可以是普通方法和泛型方法,当普通方法使用泛型的时候,我们可以省略泛型,上诉代码替换为:
public void Show<T>(T t) { Console.WriteLine(t); }是一样的结果。但是泛型类也有一个弊端,那就是失去了继承类的继承性质,如
BasePopleModel p = new Person()
{
Name="zhangsan",Age=28,Id=1,Id_No="110000198212193145",Address="beijiang",Sex="女"
};
MyGrenric<Person> gren = new MyGrenric<Person>();
gren.Show(p);
这个时候,我们的代码就会报错。那如何在泛型中保留类的基础性,使用如下语法就能做到:
当我们所有继承了BasePopleModel的子类,都可以使用这个泛型类。
3泛型接口的定义和使用
我们来看下代码,定义一个泛型接口,和定义泛型类的语法结构是一样的,他本身也具有接口的特性。代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp3 { public interface IBaseImpl<T> { int State { get; set; } void Show(T t); void Search<S>(S s,T t); } }
当我们普通类继承这个泛型接口的时候,我们会发现,继承不了,生成编译项目的时候,会提示出错误信息:如下图
那我们来试试,泛型类来继承泛型接口,看好使不好使,把我们上面创建的泛型类继承我们的接口(MyGrenric<T>:IBaseImpl<T>)如下:
public class MyGrenric<T>:IBaseImpl<T> { public int State { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public void Search<S>(S s, T t) { throw new NotImplementedException(); } public void Show(T t) { Console.WriteLine(t); } }
我们发现是能运行的.
现在问题来了,刚才我们的实例类继承泛型接口继承不了,我们的实例类继承泛型类能继承吗??,有没有什么办法,让我们的实例类继承我们的泛型接口和泛型类呢?我们先来看看,能不能实例类继承泛型类
我们会发现还是继承不了:既然前边说了,T只是一个占位符,我们可不可以显示的写出一个类呢??
我们发现,这样是可以的,没有编译错误,那么我泛型类和泛型接口的占位符都是T,那么我们使用不同 的类可以吗??,答案是否定的,绝对不可以,一个占位符只能代表一个类型,所以我们要使用不同的类型,就需要使用不同的占位符,如:
泛型约束
前边学习了这么多自定义泛型的知识,我们基本就把整个泛型学习完了,我们之前一直都是说T,S,是泛型的一个占位符,可以是任意类型,那我们可以限定这个类型吗?答案是肯定的,继续看图片
通过上诉,我们能看出,我们限定了类型,只能是Pople 类类型。限定语法,“只有在泛型类和接口之后跟WHERE 泛型占位符 :类型”。
where T: 类型值 | 说明 | 限定规范 |
class | 限定泛型只能是class 类型 | 可以有参数构造函数或无参数构造函数,不能和其他关键字一起使用 |
struct | 限定泛型只能是struct类型 | 不可以和其他类型一起使用 |
new() | 限定只能是类类型,切有无参数构造函数 | 必须有参数构造函数,不能和其他关键字一起使用 |
类类型 | 如果传入的是父类,则保留继承性质 | 无 |
值类型 | 无 | 无 |
这里就不过多演示上述内容,我们在这里只演示class ,代码如下
using System; using System.Collections.Generic; using System.Data; namespace testData { class Program { static void Main(string[] args) { BasePopleModel p = new Person() { Name="zhangsan",Age=28,Id=1,Id_No="110000198212193145",Address="beijiang",Sex="女" }; MyGrenric<BasePopleModel> gren = new MyGrenric<BasePopleModel>(); gren.Show(p); Console.Read(); } } /// <summary> /// 人的父类 /// </summary> public class BasePopleModel { public string Name { get; set; } public int Age { get; set; } public string Address { get; set; } public string Id_No { get; set; } public string Sex { get; set; } } public class Pople { public string Name { get; set; } public int Age { get; set; } public string Address { get; set; } public string Id_No { get; set; } public string Sex { get; set; } public override string ToString() { string result = "{"+$"name:{this.Name},age : {this.Age},sex : {this.Sex},no : {this.Id_No} "+"}"; return base.ToString(); } } //人的信息 public class Person: BasePopleModel { public Person() { } public int Id { get; set; } public void Show(BasePopleModel s) { throw new NotImplementedException(); } public override string ToString() { string result = "{ "+ $"name : {base.Name},age : {base.Age},sex : {base.Sex},no : {base.Id_No} , id : {this.Id}"+" }"; return result; } } public class MyGrenric<T> where T : class ,new() { public void Show(T t) { Console.WriteLine(t); } } //public interface IBaseImpl<S> where S : class //{ // int State { get; set; } // void Show(S s); //} }
总结:泛型类必须继承在泛型类上,如果作为普通类的父类,必须显示指定其类型,在约束的时候,泛型类不能指定值类型的约束。
泛型接口必须被泛型类和泛型接口继承,如果被普通接口和普通类继承,必须显示的指定类型,必须放在多个继承文件的最后。在约束的时候,不能使用new()。
本文只是介绍常用的泛型使用方向,很多其他方向没有详细介绍,常用就是泛型类的使用,并不怎么涉及到泛型的继承,如果一个项目涉及到泛型继承,证明这个项目也是快重构了。不过在开发过程中,泛型的约束是经常使用的。仅供参考
另付2.0以后提供的常用泛型如下:
2.0版的.NET框架类库提供了一个新的命名空间,System.Collections.Generic,其中包含了一些已经可以使用的泛型容器类和相关的接口。和早期版本的.NET框架提供的非泛型容器类相比,这些类和接口更高效且是类型安全的。在设计、实现自定义的容器类之前,请你考虑是否使用或继承所列出类中的一个。
下面的表格列出了新的泛型类和接口,旁边是对应的非泛型类和接口。在一些地方要特别注意,如List<T>和Dictionary<T>,新泛型类的行为(behavior)与它们所替换的非泛型类有些不同,也不完全兼容。更详细的内容,请参考System.Collections.Generic的文档
泛型类或接口 |
描述 |
对应的非泛型类型 |
Collection<T> ICollection<T> |
为泛型容器提供基类 |
CollectionBase ICollection |
Comparer<T> IComparer<T> IComparable<T> |
比较两个相同泛型类型的对象是否相等、可排序。 |
Comparer IComparer IComparable |
Dictionary<K, V> IDictionary<K,V> |
表示用键组织的键/值对集合。 |
Hashtable IDictionary |
Dictionary<K, V>.KeyCollection |
表示Dictionary<K, V>中键的集合。 |
None. |
Dictionary<K, V>.ValueCollection |
表示Dictionary<K, V>中值的集合。 |
None. |
IEnumerable<T> IEnumerator<T> |
表示可以使用foreach 迭代的集合。 |
IEnumerable IEnumerator |
KeyedCollection<T, U> |
表示有键值的集合。 |
KeyedCollection |
LinkedList<T> |
表示双向链表。 |
None. |
LinkedListNode<T> |
表示LinkedList<T>中的节点。 |
None. |
List<T> IList<T> |
使用大小可按需动态增加的数组实现 IList 接口 |
ArrayList IList |
Queue<T> |
表示对象的先进先出集合。 |
Queue |
ReadOnlyCollection<T> |
为泛型只读容器提供基类。 |
ReadOnlyCollectionBase |
SortedDictionary<K, V> |
表示键/值对的集合,这些键和值按键排序并可按照键访问,实现IComparer<T>接口。 |
SortedList |
Stack<T> |
表示对象的简单的后进先出集合。 |
Stack |
Net is as typeof 运行运算符详解 net 自定义泛型那点事的更多相关文章
- Net is as typeof 运行运算符详解
概述 在了解运行运算符的前提我们需要了解什么是RTTI ,在任何一门面向对象的语言中,都有RTTI这个概念(即 运行时). RTTI(Run-Time Type Identification),通过运 ...
- ASP.NET 运行时详解 揭开请求过程神秘面纱
对于ASP.NET开发,排在前五的话题离不开请求生命周期.像什么Cache.身份认证.Role管理.Routing映射,微软到底在请求过程中干了哪些隐秘的事,现在是时候揭晓了.抛开乌云见晴天,接下来就 ...
- ASP.NET运行时详解 集成模式和经典模式
遗留问题 在<ASP.NET运行时详解 生命周期入口分析>中遗留两个问题,包括Application的InitInternal方法执行细节.IIS6和II7经典模式请求管道管理类Appli ...
- CentOS Linux使用crontab运行定时任务详解
参考博文: (总结)CentOS Linux使用crontab运行定时任务详解
- Nginx与PHP-FPM运行原理详解
目录 1. 代理与反向代理 1. 正向代理:访问google.com 2. 反向代理:通过反向代理实现负载均衡 2. 初识Nginx与PHP-FPM 1. Nginx是什么 2. CGI与FastCG ...
- JavaScript运行机制详解
JavaScript运行机制详解 var test = function(){ alert("test"); } var test2 = function(){ alert(& ...
- JVM运行原理详解
1.JVM简析: 作为一名Java使用者,掌握JVM的体系结构也是很有必要的. 说起Java,我们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成:Ja ...
- 「JVM」知识点详解一:JVM运行原理详解
前言 JVM 一直都是面试的必考点,大家都知道,但是要把它搞清楚又好像不是特别容易.JVM 的知识点太散,不系统,今天带大家详细的了解一下jvm的运行原理. 正文 1 什么是JVM? JVM是Java ...
- java 泛型详解(普通泛型、 通配符、 泛型接口)
java 泛型详解(普通泛型. 通配符. 泛型接口) JDK1.5 令我们期待很久,可是当他发布的时候却更换版本号为5.0.这说明Java已经有大幅度的变化.本文将讲解JDK5.0支持的新功能---- ...
随机推荐
- ACM-ICPC 2018 沈阳赛区网络预赛 J树分块
J. Ka Chang Given a rooted tree ( the root is node 11 ) of NN nodes. Initially, each node has zero p ...
- [错误处理]python大小写敏感,关键字不要写错
今天调试程序,发现了一个极为隐蔽的bug. True False关键字大小写写错了,然后半天没找出问题所在.
- 面向对象编程(二)封装--构造方法,this关键字,static关键字,方法重载
面向对象三大特点:封装.继承.多态 封装概念 ① 将东西包装在一起,然后以新的完整形式呈现出来: 将方法和字段一起包装到一个单元中,单元以类的形式实现; ② 信息隐藏,隐藏对象的实现细节,不让 ...
- POJ 1690 (Your)((Term)((Project)))
(Your)((Term)((Project))) Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 2912 Accept ...
- Spring 依赖注入(一、注入方式)
首先装配一个实体类People package com.maya.model; public class People { private int id; private String name; p ...
- Tarjan的强联通分量
求强联通分量有很多种. <C++信息学奥赛一本通> 中讲过一个dfs求强联通分量的算法Kosdaraju,为了骗字数我就待会简单的说说.然而我们这篇文章的主体是Tarjan,所以我肯定说 ...
- [UOJ#276]【清华集训2016】汽水
[UOJ#276][清华集训2016]汽水 试题描述 牛牛来到了一个盛产汽水的国度旅行. 这个国度的地图上有 \(n\) 个城市,这些城市之间用 \(n−1\) 条道路连接,任意两个城市之间,都存在一 ...
- iOS-多线程(2)
多线程之NSOperation: 多线程的优点: 使用线程可以把占据时间长的程序中的任务呀放到后台去处理 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显 ...
- vue的过渡动画在除了chrome浏览器外的浏览器下不正常的问题
为过渡动画添加mode="out-in"在其它浏览器下面就能正常的使用了
- 【BZOJ2286】消耗战(虚树,DFS序,树形DP)
题意:一棵N个点的树上有若干个关键点,每条边有一个边权,现在要将这些关键点到1的路径全部切断,切断一条边的代价就是边权. 共有M组询问,每组询问有k[i]个关键点,对于每组询问求出完成任务的最小代价. ...