日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

泛型最佳實(shí)踐C#

系統(tǒng) 2212 0
什么時(shí)候我不應(yīng)該使用泛型?對泛型我應(yīng)該使用什么命名規(guī)范?我應(yīng)該在泛型接口上面添加約束嗎?
如何處置(Dispose)泛型接口?可以對一般類型參數(shù)進(jìn)行類型轉(zhuǎn)換嗎?
對泛型類如何同步多線程訪問?如何序列化泛型類?

什么時(shí)候我不應(yīng)該使用泛型?

????????不使用泛型的主要原因就是跨目標(biāo)(cross
- targeting)——如果你要在.NET? 1 .1和.NET? 2 .0下編譯相同的代碼,那么由于只有.NET? 2 .0支持泛型,你就不能夠使用泛型。


對泛型我應(yīng)該使用什么命名規(guī)范?

????????我建議使用一個(gè)單獨(dú)的大寫字母來表示一般類型參數(shù)。如果你對類型參數(shù)沒有其他的跟上下文有關(guān)的信息(additional?contextual?information),你應(yīng)該使用字母T:

public ? class ?MyClass < T >
{ }
??????
?在所有其他場合下,微軟正式的對泛型的的命名規(guī)范指導(dǎo)是:

一般類型參數(shù)要有描述性的名字,除非一個(gè)單獨(dú)的字母已經(jīng)表示得很清楚,再增加描述性的名字也沒有多大用處。

public ? interface ?ISessionChannel < TSession > ?
{ }
public ? delegate ?TOutput?Converter < TInput,TOutput > (TInput?from);
可以考慮在一般類型參數(shù)的名字中表示出添加給該一般類型參數(shù)的約束。例如,一個(gè)被約束到ISession接口的參數(shù)可以起名為TSession。
我應(yīng)該在泛型接口上面添加約束嗎?

????????接口可以為其使用的范型類型添加約束,例如:??

public ? interface ?ILinkedList < T > ?where?T?:?IComparable < T >
{ }
??但是,你應(yīng)該小心,在接口層面上定義約束還隱含有另外一層意思。為了強(qiáng)調(diào)接口與實(shí)現(xiàn)分離的思想,接口不應(yīng)該包括任何一點(diǎn)實(shí)現(xiàn)的細(xì)節(jié)。雖然有很多方法可以用來實(shí)現(xiàn)范型接口,但是使用特定的類型參數(shù)畢竟是一種實(shí)現(xiàn)的細(xì)節(jié)。約束通常情況下會(huì)更加耦合(couple)接口和特定的實(shí)現(xiàn)。

????????更好的方法是,為實(shí)現(xiàn)范型接口的類添加約束,保持接口本身沒有約束:

public ? class ?LinkedList < T > ?:?ILinkedList < T > ?where?T?:?IComparable < T >
{
???
// Rest?of?the?implementation??
}

如何處置(Dispose)泛型接口?

??????在C#和Visual?Basic中,如果你把一個(gè)一般類型參數(shù)的對象放在using語句中,編譯器無法知道客戶端(client)指定的實(shí)際類型是否支持IDisposable接口。因此編譯器不允許在using語句中使用一般類型參數(shù)的實(shí)例。

public ? class ?MyClass < T > ?
{
???
public ? void ?SomeMethod(T?t)
???
{
??????
using (t) // Does?not?compile?
?????? { }
???}

}

當(dāng)然,你可以強(qiáng)制約束類型參數(shù)支持IDisposable接口:

public ? class ?MyClass < T > ?where?T?:?IDisposable?
{
???
public ? void ?SomeMethod(T?t)
???
{
??????
using (t)
??????
{ }
???}

}

?????但是你不應(yīng)該這么做。這樣做的問題在于你不能使用接口作為類型參數(shù)了,即使這個(gè)接口的基礎(chǔ)類型(underlying?type)支持IDisposable也不行:

public ? interface ?IMyInterface
{}
public ? class ?MyOtherClass?:?IMyInterface,IDisposable?
{ }
public ? class ?MyClass < T > ?where?T?:?IDisposable?
{
???
public ? void ?SomeMethod(T?t)
???
{
??????
using (t)
??????
{ }
???}

}

MyOtherClass?myOtherClass?
= ? new ?MyOtherClass();
MyClass
< IMyInterface > ?obj? = ? new ?MyClass < IMyInterface > (); // Does?not?compile
obj.SomeMethod(myOtherClass);?
??作為替代,我建議你在using語句里對一般類型參數(shù)使用C#中的as操作符或者Visual?Basic中的TryCast操作符來允許接口作為一般類型參數(shù)使用:


public ? class ?MyClass < T > ?
{
???
public ? void ?SomeMethod(T?t)
???
{
??????
using (t? as ?IDisposable)
??????
{ }
???}

}

可以對一般類型參數(shù)進(jìn)行類型轉(zhuǎn)換嗎?

????????對于隱式轉(zhuǎn)換,編譯器只允許將一般類型參數(shù)轉(zhuǎn)換為object類型,或者其約束里指定的那個(gè)類型:

interface ?ISomeInterface
{ }
class ?BaseClass
{ }
class ?MyClass < T > ?where?T?:?BaseClass,ISomeInterface
{
???
void ?SomeMethod(T?t)
???
{
??????ISomeInterface?obj1?
= ?t;
??????BaseClass??????obj2?
= ?t;
??????
object ?????????obj3? = ?t;
???}

}

這種隱式轉(zhuǎn)換當(dāng)然是類型安全的,因?yàn)闊o效的轉(zhuǎn)換在編譯時(shí)就會(huì)被發(fā)現(xiàn)。

????????對于顯示轉(zhuǎn)換,編譯器允許將一般類型參數(shù)轉(zhuǎn)換到任何接口,但是不能轉(zhuǎn)換為類:

interface ?ISomeInterface
{ }
class ?SomeClass
{ }
class ?MyClass < T > ?
{
???
void ?SomeMethod(T?t)
???
{
??????ISomeInterface?obj1?
= ?(ISomeInterface)t; // Compiles
??????SomeClass??????obj2? = ?(SomeClass)t;????? // Does?not?compile
???}

}

?但是,你可以通過使用一個(gè)臨時(shí)的object類型變量來強(qiáng)制將一般類型參數(shù)轉(zhuǎn)到到任何其他類型:

class ?MyOtherClass
{ }

class ?MyClass < T > ?
{
??
???
void ?SomeMethod(T?t)
???
???
{
??????
object ?temp? = ?t;
??????MyOtherClass?obj?
= ?(MyOtherClass)temp;
???
???}

}

毫無疑問,這樣的顯示轉(zhuǎn)換是很危險(xiǎn)的,因?yàn)槿绻麑?shí)際使用的替代一般類型參數(shù)的類型不是從你要轉(zhuǎn)換到的類型那里繼承的話,就可能在運(yùn)行時(shí)拋出異常。

????????為了避免這種轉(zhuǎn)換時(shí)有異常的風(fēng)險(xiǎn),一個(gè)更好的辦法是使用is或者as操作符。如果一般類型參數(shù)是(
is )要查詢的類型, is ?操作符會(huì)返回true,而as操作符會(huì)在兩個(gè)類型兼容的時(shí)候執(zhí)行轉(zhuǎn)換,否則將返回null。

public ? class ?MyClass < T > ?
{
???
public ? void ?SomeMethod(T?t)
???
{
??????
if (t? is ? int )
??????
{ } ?

??????
if (t? is ?LinkedList < int , string > )
??????
{ }

??????
string ?str? = ?t? as ? string ;
??????
if (str? != ? null )
??????
{ }

??????LinkedList
< int , string > ?list? = ?t? as ?LinkedList < int , string > ;
??????
if (list? != ? null )
??????
{ }
???}

}




對泛型類如何同步多線程訪問?

????????通常來說,你不應(yīng)該在一般類型參數(shù)上應(yīng)用Monitor。這是因?yàn)镸onitor只能用于引用類型。當(dāng)你使用范型的時(shí)候,編譯器不能預(yù)先判斷你將會(huì)提供一個(gè)引用類型還是值類型的類型參數(shù)。在C#中,編譯器會(huì)允許你使用lock語句,但是如果你提供了一個(gè)值類型作為類型參數(shù),lock語句在運(yùn)行時(shí)將不起作用。在Visual?Basic中,編譯器如果不能確定一般類型參數(shù)是一個(gè)引用類型,它將不允許在一般類型參數(shù)上面使用SyncLock。

????????在C#和Visual?Basic中,唯一你可以安全地將一般類型參數(shù)鎖住的時(shí)候,是你將一般類型參數(shù)限制為引用類型,要么添加約束使其為引用類型,要么從一個(gè)基類中繼承:

public ? class ?MyClass < T > ?where?T?:? class
{..}

public ? class ?SomeClass
{ }
public ? class ?MyClass < T > ?where?T?:?SomeClass
{ }
?????然而,通常對于同步來說,最好避免部分地鎖住單獨(dú)的成員變量,因?yàn)檫@會(huì)增加死鎖的可能性。

如何序列化泛型類?

????????包括了一般類型參數(shù)作為成員的范型類是可以被標(biāo)記為序列化的:

[Serializable]
public ? class ?MySerializableClass < T >
{
???T?m_T;
}

??但是,在這種情況下,只有指定的類型參數(shù)可以被序列化時(shí),范型類才可以被序列化。看下面的代碼:


public ? class ?SomeClass
{}
MySerializableClass
< SomeClass > ?obj;
??obj不能被序列化,因?yàn)轭愋蛥?shù)SomeClass不可以被序列化。因此,MySerializableClass
< T > 可能可以,也可能不可以被序列化,取決于使用的一般類型參數(shù)。這樣可能導(dǎo)致在運(yùn)行時(shí)丟失數(shù)據(jù)或者系統(tǒng)崩潰,因?yàn)榭蛻魬?yīng)用程序可能不能夠保持對象的狀態(tài)。

????????目前,.NET沒有提供將一般類型參數(shù)約束為可序列化的機(jī)制。解決辦法是在運(yùn)行時(shí)在使用這個(gè)類型之前單獨(dú)進(jìn)行檢查,并且在任何損害發(fā)生之前馬上中止使用。你可以把這個(gè)運(yùn)行時(shí)的驗(yàn)證放在靜態(tài)構(gòu)造器里面:

[Serializable]
class ?MySerializableClass < T >
{
???T?m_T;

???
static ?MySerializableClass()???
???
{
??????ConstrainType(
typeof (T));
???}

???
static ? void ?ConstrainType(Type?type)
???
{
??????
bool ?serializable? = ?type.IsSerializable;
??????
if (serializable? == ? false )
??????
{
?????????
string ?message? = ? " The?type? " ? + ?type? + ? " ?is?not?serializable " ;
?????????
throw ? new ?InvalidOperationException(message);
??????}

???}

}

?靜態(tài)構(gòu)造器對每一個(gè)應(yīng)用程序域的每一個(gè)類型只執(zhí)行一次,而且是在類型第一次被請求實(shí)例化之前。盡管你有一些通過編程的方式來在運(yùn)行時(shí)進(jìn)行判斷和執(zhí)行檢查,但是這種在靜態(tài)構(gòu)造器里面執(zhí)行約束驗(yàn)證的技術(shù),對任何無法在編譯時(shí)進(jìn)行檢查的約束都適用。

泛型最佳實(shí)踐C#


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會(huì)非常 感謝您的哦?。?!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 蒲城县| 宁化县| 祁连县| 如皋市| 无棣县| 郑州市| 方山县| 阜康市| 墨脱县| 四子王旗| 廊坊市| 朔州市| 张北县| 大新县| 昭苏县| 龙游县| 乌鲁木齐县| 托克逊县| 陆丰市| 昌吉市| 大厂| 岳普湖县| 页游| 灵丘县| 洮南市| 京山县| 翁源县| 泸西县| 健康| 蓬安县| 武陟县| 龙岩市| 北安市| 阳泉市| 施甸县| 旌德县| 宜宾市| 通州区| 商河县| 科技| 兴宁市|