泛型最佳实践C#

起名 1哟时候自己非该利用泛型?对泛型我应当利用什么命名规范?我该当泛型接口上边长约束为?
起名 2如何处置(Dispose)泛型接口?可以针对一般项目参数举办类型转换吗?
起名 3本着泛型类咋样共同多线程访问?怎么着系列化泛型类?
起名 4
起名 5哎时候自己莫该用泛型?
起名 6
起名 7        不使用泛型的第一缘由就是过目的(cross-targeting)——假若你假诺在.NET 1.1同.NET 2.0生编译相同之代码,那么由单独有.NET 2.0襄助泛型,你不怕无克以泛型。
起名 8
起名 9
起名 10本着泛型我应当使啊命名规范?
起名 11
起名 12        我提议采纳一个独自的丰裕写字母来表示一般品种参数。假设你针对项目参数没有其它的跟上下和有关的信(additional contextual information),你应有以字母T:
起名 13
起名 14public class MyClass<T>
起名 15起名 16起名 17{起名 18}
起名 19      
起名 20 在装有其他场所下,微软正式的针对性泛型的底命名规范指导是:
起名 21
起名 22诚如品种参数要有描述性的名字,除非一个独自的字母就代表得可怜知,再添描述性的讳也远非多好用处。
起名 23
起名 24public interface ISessionChannel<TSession> 
起名 25起名 26起名 27{起名 28}
起名 29public delegate TOutput Converter<TInput,TOutput>(TInput from);
起名 30好考虑于相似项目参数的名字被意味着来上加给该一般项目参数的羁绊。例如,一个于律到ISession接口的参数可以起名为TSession。
起名 31自当以泛型接口下面长约束为?
起名 32
起名 33        接口可以呢这以的范型类型丰盛约束,例如:  
起名 34
起名 35public interface ILinkedList<T> where T : IComparable<T>
起名 36起名 37起名 38{起名 39}
起名 40  可是,你该小心,在接口层面达到定义约束还包含有此外一重合意思。为了强调接口和贯彻分离的思想,接口不应该包括外一点实现的细节。即便发出过多办法好据此来贯彻范型接口,不过用一定的型参数毕竟是均等种植实现之底细。约束常常情状下会越来越耦合(couple)接口及一定的兑现。
起名 41
起名 42        更好的情势是,为实现范型接口的类添加约束,保持接口本身没有约束:
起名 43
起名 44public class LinkedList<T> : ILinkedList<T> where T : IComparable<T>
起名 45起名 46起名 47{
起名 48   //Rest of the implementation  
起名 49}
起名 50什么样办(Dispose)泛型接口?
起名 51
起名 52      在C#暨Visual Basic中,假若您拿一个貌似项目参数的目的在using语句被,编译器无法知晓客户端(client)指定的其实类型是否辅助IDisposable接口。由此编译器不允以using语句被行使相似项目参数的实例。
起名 53
起名 54public class MyClass<T> 
起名 55起名 56起名 57{
起名 58   public void SomeMethod(T t)
起名 59起名 60   起名 61{
起名 62      using(t)//Does not compile 
起名 63起名 64      起名 65{起名 66}
起名 67   }
起名 68}
起名 69本来,你得强制约束类型参数扶助IDisposable接口:
起名 70
起名 71public class MyClass<T> where T : IDisposable 
起名 72起名 73起名 74{
起名 75   public void SomeMethod(T t)
起名 76起名 77   起名 78{
起名 79      using(t)
起名 80起名 81      起名 82{起名 83}
起名 84   }
起名 85}
起名 86     然则若莫该如此做。这样做的题材在你免克应用接口作为项目参数了,即便是接口的底子项目(underlying type)帮忙IDisposable也深:
起名 87
起名 88public interface IMyInterface
起名 89起名 90起名 91{}
起名 92public class MyOtherClass : IMyInterface,IDisposable 
起名 93起名 94起名 95{起名 96}
起名 97public class MyClass<T> where T : IDisposable 
起名 98起名 99起名 100{
起名 101   public void SomeMethod(T t)
起名 102起名 103   起名 104{
起名 105      using(t)
起名 106起名 107      起名 108{起名 109}
起名 110   }
起名 111}
起名 112MyOtherClass myOtherClass = new MyOtherClass();
起名 113MyClass<IMyInterface> obj = new MyClass<IMyInterface>();//Does not compile
起名 114obj.SomeMethod(myOtherClass); 
起名 115  作为代表,我提议乃在using语句里对一般品种参数使用C#屡遭之as操作符或者Visual Basic中之TryCast操作符来允许接口作为一般项目参数使用:
起名 116
起名 117
起名 118public class MyClass<T> 
起名 119起名 120起名 121{
起名 122   public void SomeMethod(T t)
起名 123起名 124   起名 125{
起名 126      using(t as IDisposable)
起名 127起名 128      起名 129{起名 130}
起名 131   }
起名 132}
起名 133足本着一般项目参数举办类型转换吗?
起名 134
起名 135        对于隐式转换,编译器只同意以一般项目参数转换为object类型,或者其格里指定的酷型:
起名 136
起名 137interface ISomeInterface
起名 138起名 139起名 140{起名 141}
起名 142class BaseClass
起名 143起名 144起名 145{起名 146}
起名 147class MyClass<T> where T : BaseClass,ISomeInterface
起名 148起名 149起名 150{
起名 151   void SomeMethod(T t)
起名 152起名 153   起名 154{
起名 155      ISomeInterface obj1 = t;
起名 156      BaseClass      obj2 = t;
起名 157      object         obj3 = t;
起名 158   }
起名 159}
起名 160那种隐式转换当然是种安全的,因为无效的变换在编译时虽会吃察觉。
起名 161
起名 162        对于突显转换,编译器允许将一般品种参数转换来其它接口,不过非克转换为接近:
起名 163
起名 164interface ISomeInterface
起名 165起名 166起名 167{起名 168}
起名 169class SomeClass
起名 170起名 171起名 172{起名 173}
起名 174class MyClass<T> 
起名 175起名 176起名 177{
起名 178   void SomeMethod(T t)
起名 179起名 180   起名 181{
起名 182      ISomeInterface obj1 = (ISomeInterface)t;//Compiles
起名 183      SomeClass      obj2 = (SomeClass)t;     //Does not compile
起名 184   }
起名 185}
起名 186 不过,你得经过动用一个现之object类型变量来强制将一般项目参数转至到外另外项目:
起名 187
起名 188class MyOtherClass
起名 189起名 190起名 191{起名 192}
起名 193
起名 194class MyClass<T> 
起名 195起名 196起名 197{
起名 198  
起名 199   void SomeMethod(T t)
起名 200   
起名 201起名 202   起名 203{
起名 204      object temp = t;
起名 205      MyOtherClass obj = (MyOtherClass)temp;
起名 206   
起名 207   }
起名 208}
起名 209必然,这样的显得转换是老悬的,因为若实在利用的代一般品种参数的类型不是打您要更换来的门类这里继承的话,就可能于运作时抛来特别。
起名 210
起名 211        为了避免这种转移时发出老的高风险,一个再好的点子是使用is或者as操作符。如若相似品种参数是(is)要查询的序列,is 操作符会重临true,而as操作符会在少数个体系兼容的时刻实施转换,否则将赶回null。
起名 212
起名 213public class MyClass<T> 
起名 214起名 215起名 216{
起名 217   public void SomeMethod(T t)
起名 218起名 219   起名 220{
起名 221      if(t is int)
起名 222起名 223      起名 224{起名 225
起名 226
起名 227      if(t is LinkedList<int,string>)
起名 228起名 229      起名 230{起名 231}
起名 232
起名 233      string str = t as string;
起名 234      if(str != null)
起名 235起名 236      起名 237{起名 238}
起名 239
起名 240      LinkedList<int,string> list = t as LinkedList<int,string>;
起名 241      if(list != null)
起名 242起名 243      起名 244{起名 245}
起名 246   }
起名 247}
起名 248
起名 249
起名 250
起名 251对泛型类怎么样同步多线程访问?
起名 252
起名 253        通常来说,你切莫应有以相似项目参数达到使用Monitor。这是为Monitor只能用来引用类型。当您用范型的时刻,编译器不可知预先判断你将会师供一个援类型或者值类型的序列参数。在C#蒙,编译器会同意你用lock语句,可是一旦您提供了一个值类型作为项目参数,lock语句以运行时将不起效能。在Visual Basic中,编译器假诺不可能确定一般项目参数是一个援类型,它用非容许在一般项目参数方面用SyncLock。
起名 254
起名 255        在C#和Visual Basic中,唯一你可以安全地将一般品种参数锁住的时候,是你以一般品种参数限制也援类型,要么添加约束若其为援类型,要么从一个基类中继承:
起名 256
起名 257public class MyClass<T> where T : class
起名 258起名 259起名 260{..}
起名 261
起名 262public class SomeClass
起名 263起名 264起名 265{起名 266}
起名 267public class MyClass<T> where T : SomeClass
起名 268起名 269起名 270{起名 271}
起名 272     然则,日常对联合来说,最好制止有些地锁住单独的成员变量,因为就会追加死锁的可能性。
起名 273
起名 274何以系列化泛型类?
起名 275
起名 276        包括了一般项目参数作为成员的范型类是好叫记为系列化的:
起名 277
起名 278[Serializable]
起名 279public class MySerializableClass<T>
起名 280起名 281起名 282{
起名 283   T m_T;
起名 284}
起名 285  不过,在这种情景下,只有指定的项目参数能够于系列化时,范型类才可给序列化。看下的代码:
起名 286
起名 287
起名 288public class SomeClass
起名 289起名 290起名 291{}
起名 292MySerializableClass<SomeClass> obj;
起名 293  obj不可能吃系列化,因为品种参数SomeClass不得以于体系化。由此,MySerializableClass<T>可能好,也可能不得以给系列化,取决于使用的貌似项目参数。这样或造成在运作时少数据要系统崩溃,因为客户应用程序可能不能保持对象的状态。
起名 294
起名 295        近期,.NET没有供用一般项目参数约束为而系列化的机制。解决办法是以运作时在采纳这多少个序列以前单独开展检查,并且在另外伤害暴发往日就刹车使用。你可拿此运行时之印证放在静态构造器里面:
起名 296
起名 297[Serializable]
起名 298class MySerializableClass<T>
起名 299起名 300起名 301{
起名 302   T m_T;
起名 303
起名 304   static MySerializableClass()   
起名 305起名 306   起名 307{
起名 308      ConstrainType(typeof(T));
起名 309   }
起名 310   static void ConstrainType(Type type)
起名 311起名 312   起名 313{
起名 314      bool serializable = type.IsSerializable;
起名 315      if(serializable == false)
起名 316起名 317      起名 318{
起名 319         string message = “The type ” + type + ” is not serializable”;
起名 320         throw new InvalidOperationException(message);
起名 321      }
起名 322   }
起名 323}
起名 324 静态构造器对各样一个应用程序域的各级一个项目只举办同样不行,而且是当项目第一不善让求实例化在此以前。即便你生出局部透过编程的道来在运转时举行判断与施行检查,不过这种当静态构造器里面实践约束验证的技能,对其他不可能在编译时开展检查的封锁都适用。
起名 325
起名 326

函数的传参

咱告知mylen函数要算的字符串是何许人也,这一个过程即为做 传送参数,简称传参,咱调用函数时传递的斯“hello
world”和定义函数时的s1就是参数

毋庸置疑出席形参

参数还有个别:

咱调用函数时传递的此“hello
world”被叫作事实上参数,盖那是实际的假设交函数的情,简称实参。

概念函数时的s1,只是一个变量的名字,被称呼花样参数,因为在概念函数的上她仅仅是一个情势,表示此发出一个参数,简称形参。  

传送多少个参数

参数可以传递多只,多独参数之间因此逗号分割。

def mymax(x,y):
    the_max = x if x > y else y
    return the_max

ma = mymax(10,20)
print(ma)

  

岗位参数

  站在实参角度

    1.据职位传值

def mymax(x,y):
    #此时x=10,y=20
    the_max = x if x > y else y
    return the_max

ma = mymax(10,20)
print(ma)

    2.第一字参数

def mymax(x,y):
    #此时x = 20,y = 10
    print(x,y)
    the_max = x if x > y else y
    return the_max

ma = mymax(y = 10,x = 20)
print(ma)

    3.职务,关键字简单栽样式的混用

def mymax(x,y):
    #此时x = 10,y = 20
    print(x,y)
    the_max = x if x > y else y
    return the_max

ma = mymax(10,y = 20)
print(ma)

  

      正确用法

      问题一样:地方参数必须以重点字参数的眼前

      问题二:对于一个形参只可以赋值一破    

  站在形參角度

    地点参数必须传值

def mymax(x,y):
    #此时x = 10,y = 20
    print(x,y)
    the_max = x if x > y else y
    return the_max

#调用mymax不传递参数
ma = mymax()
print(ma)

#结果
TypeError: mymax() missing 2 required positional arguments: 'x' and 'y'

  

默认参数

    1.正常化使用

起名,      使用方法

      为啥而有默认参数:将变相比较粗的价值设置成默认参数

    2.默服参数的概念

def stu_info(name,sex = "male"):
    """打印学生信息函数,由于班中大部分学生都是男生,
        所以设置默认参数sex的默认值为'male'
    """
    print(name,sex)


stu_info('alex')
stu_info('eva','female')

  3.参数陷阱:默认参数是一个可变数据类型

def defult_param(a,l = []):
    l.append(a)
    print(l)

defult_param('alex')
defult_param('egon')

  

动态参数

  按岗位传值多余的参数仍然因为args统一接受,保存成一个元组的情势,

#*args (按职务传参,元组)

#\*kwargs (按紧要性字传参,字典)*

 

def mysum(*args):
    the_sum = 0
    for i in args:
        the_sum+=i
    return the_sum

the_sum = mysum(1,2,3,4)
print(the_sum)


-------------------------------------------------------------------------------------------


def stu_info(**kwargs):
    print(kwargs)
    print(kwargs['name'],kwargs['sex'])

stu_info(name = 'alex',sex = 'male')

函数使用小节 

概念函数的平整:

1.定义:def 关键词开头,空格之后接函数名称和圆括号()。
2.参数:圆括号用来接收参数。若传入多个参数,参数之间用逗号分割。
    参数可以定义多个,也可以不定义。
    参数有很多种,如果涉及到多种参数的定义,应始终遵循位置参数、*args、默认参数、**kwargs顺序定义。
    如上述定义过程中某参数类型缺省,其他参数依旧遵循上述排序
3.注释:函数的第一行语句应该添加注释。
4.函数体:函数内容以冒号起始,并且缩进。
5.返回值:return [表达式] 结束函数。不带表达式的return相当于返回 None

def 函数名(参数1,参数2,*args,默认参数,**kwargs):
        """注释:函数功能和参数说明"""
        函数体
        ……
        return 返回值  

调用函数的条条框框

1.函数名()
    函数名后面+圆括号就是函数的调用。
2.参数:
    圆括号用来接收参数。
    若传入多个参数:
        应按先位置传值,再按关键字传值
        具体的传入顺序应按照函数定义的参数情况而定
      

3.返回值
    如果函数有返回值,还应该定义“变量”接收返回值
    如果返回值有多个,也可以用多个变量来接收,变量数应和返回值数目一致

无返回值的情况:
函数名()

有返回值的情况:
变量 = 函数名()

多个变量接收多返回值:
变量1,变量2,... = 函数名()

  

 

  

 

函数的施行各样

咱才待以函数的尾声加上一个return,return后边写上而而回到的值就是可以了。

接通下去,我们固然来琢磨一下者return的用法。

return关键字的意

  return
是一个重大字,在pycharm里,你会晤看其成粉色了。你必一字不差的拿这一个单词给背下去。

  这一个词翻译过来就是是“再次回到”,所以大家无写于return前边的值叫“重返值”

一经钻再次来到值,我们还要亮回值有几乎种植状态:分别是绝非回到值、重临一个值、再次回到多独价值

不曾重回值

  不写return的动静下,会默认再次来到一个None:大家形容的率先单函数,就没写return,这即是尚未重临值的一律种植境况。 

但是写return,前面不写其他情节,也会回None,有的同学会奇怪,既然没有设赶回的值,完全可免写return,为什么还要写单return呢?这里我们若说一样下return的旁用法,就是倘遇见return,为止所有函数。  

#函数定义
def mylen():
    """计算s1的长度"""
    s1 = "hello world"
    length = 0
    for i in s1:
        length = length+1
    return length

#函数调用
str_len = mylen()
print('str_len : %s'%str_len)

回到多单价值

  可以回到任意多独、任意数据类型的价值

def ret_demo1():                #返回值如下
    return 1                    #1
def ret_demo2():
    return 1,2                  #(1,2)
def ret_demo3():
    return ['a','b']            #['a','b']
def ret_demo4():
    return 1,[],                #(1,[])
def ret_demo5():
    return 1,(1,2),{'a':'b'}    #(1, (1, 2), {'a': 'b'}),以上都为一个值接收
def ret_demo6():       
   return 1,                   #(1,)返回的也是个元组   
c= ret_demo*()
print(c)
---------------------------------------------------------------------------
def ret_demo5():
    return 1,(1,2),{'a':'b'} 
a,b,c= ret_demo5()              #返回多个值,就用多个值接收 1 (1, 2) {'a': 'b'}
print(a,b,c)

 总计:当回一个价值的下就是独字符串,当回三个价的时候是因元组的样式重临,假设return
‘a’,重回的即便是a。

python函数基础

一.函数

1.函数简介

函数是公司好的,可重复使用的,用来贯彻单一,或互相关联效应的代码段。

函数能提升运用的模块性,和代码的再次利用率。你已通晓Python提供了成百上千内建函数,比如print()。但你吗可以好创立函数,这让叫做用户从定义函数。

1)为何用函数:

  然后现在发出一个需要,让您算’hello world’的长短,你怎么总括?

1 s1 = "hello world"
2 length = 0
3 for i in s1:
4     length = length+1
5 
6 print(length)

吓了,功能实现了,相当完美。然后现在又出了一个需要,要总括其它一个字符串的长,”hello
hx”.

 1 s1 = "hello world"
 2 length = 0
 3 for i in s1:
 4     length = length+1
 5 
 6 print(length)
 7 
 8 s2 = "hello eva"
 9 length = 0
10 for i in s2:
11     length = length+1
12 
13 print(length)   
结果:第一个程序输出是11,第二个程序输出是9。

然实在可以兑现len方法的效率,不过究竟感到不是这完美?为啥呢?

首先,在此以前要我们实施len方法就得从来用到一个字符串的尺寸了,现在为落实均等之效果我们拿同之代码写了重重遍
—— 代码冗余

从,在此之前大家特写少句话读起来吧充分粗略,一看即知就片词代码是当测算长度,可是刚刚的代码却未那么爱读懂
—— 可读性差

print(len(s1))
print(len(s2))

函数的重临值

#函数定义
def mylen():
    """计算s1的长度"""
    s1 = "hello world"
    length = 0
    for i in s1:
        length = length+1
    print(length)

#函数调用
str_len = mylen()      由于没有返回值,所以str_len接收到的是None,所以打印的也是None
print('str_len : %s'%str_len)

设若您尽及时段代码,拿到的str_len
值为None,这表明我们立时段代码什么啊没有被你回去。

这就是说哪吃其为想len函数一样重回值呢?

#函数定义
def mylen():
    """计算s1的长度"""
    s1 = "hello world"
    length = 0
    for i in s1:
        length = length+1
    return length

#函数调用
str_len = mylen()
print('str_len : %s'%str_len)
结果:返回11

起名 327

 

 

 

  

 

乍认识函数定义及调用

  函数的出三受到不同的参数:

  普通参数

  默认参数

  动态参数

概念函数的几点元素:

定义:def
关键词起,空格之后接函数名及圆括声泪俱下(),最终还有一个”:”。

   def
是永恒的,不克换,必须是接二连三的def三单字母,不能分开。。。它们而密切相爱的当合。

   空格
为了用def关键字与函数号称分别,必须空(四声),当然你得空2格、3格要么您想空多少还举行,但正常人如故空1格。

   函数叫作:函数叫作只可以分包字符串、下划线和数字都非克为数字开端。尽管函数名好凭起,但咱被函数起名字或者如尽可能简单,并会公布函数功用

   括号:是须加以的,先变更问啊底要来括号,总的丰硕括号就对了!

注释:列一个函数都应当对职能与参数举行相应的验证,应该写在函数上边第一执行。以增进代码的可读性。

调用:就是 函数名() 要记加上括号

#函数定义
def mylen(s1):
    """计算s1的长度"""
    length = 0
    for i in s1:
        length = length+1
    return length

#函数调用
str_len = mylen("hello world")
print('str_len : %s'%str_len) 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图