国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

自引用泛型模式分析

2019-11-17 03:14:28
字體:
供稿:網(wǎng)友

自引用泛型模式分析

曾經(jīng)有人問我這樣一個問題:如何迫使子類提供無參構(gòu)造函數(shù)。當(dāng)時給出的答案是讓子類實(shí)現(xiàn)這樣一個接口。

    public interface IMustHaveParameterLessConstructor<T>        where T : IMustHaveParameterLessConstructor<T>, new()    {    }

這種在泛型參數(shù)中引用自身的技法,還有個名字,叫做“Self-Referencing Generics”模式。這個技法在C++中已經(jīng)被使用了20多年,只不過叫做Curiously Recurring Template。

這個技法可以用來實(shí)現(xiàn)不少有用的功能。比如為所有子類實(shí)現(xiàn)Singleton模式

     public class Singleton<T>        where T : new()    {        PRivate static readonly T instance = new T();        public static T Instance        {            get { return instance; }        }    }    public class Model : Singleton<Model>    {    }

下面談?wù)勥@個技法的劣勢。

首先,它影響代碼的可讀性,比如說用到這種程度的時候。

    public interface IComponent<T>    { }    public interface IComponentProvider<TComponent>        where TComponent : IComponent<IComponentProvider<TComponent>>    { }    public interface IComponentProviderWorkaround<TComponent, TSelf>        where TComponent : IComponent<TSelf>        where TSelf : IComponentProviderWorkaround<TComponent, TSelf>    { }

這就是自找麻煩了。別人讀起來也會想罵人。

其次,這個技法其實(shí)是反面向?qū)ο蟮?。如果你的類繼承層次多于一層,就會產(chǎn)生問題。

Eric Lippert在其博文《Curiouser and curiouser》中從繼承關(guān)系的邏輯合理性的角度進(jìn)行了分析。本質(zhì)上講,自引用泛型違反了里氏替換原則。下面節(jié)選了一些要點(diǎn)。

It seems like an abuse of a mechanism rather than the modeling of a concept from the program's "business domain"

……

My advice is to think very hard before you implement this sort of curious pattern in C#; do the benefits to the customer really outweigh the costs associated with the mental burden you're placing on the code maintainers?

Eric文中的例子還是很溫和的,至少沒有導(dǎo)致什么編譯錯誤或是警告。于是就被一些人無視了。

那么我來寫個能出編譯錯誤的例子。

    public interface SoapArgs<out T>        where T : SoapArgs<T>    {    }    public class GenericSoapArgs<T> : SoapArgs<GenericSoapArgs<T>>    {    }    public class DerivedGenericSoapArgs<T> : GenericSoapArgs<T>    {    }

這三個類(或接口)的關(guān)系很一目了然對吧。又有這樣一個函數(shù),負(fù)責(zé)把SoapArgs發(fā)出去。

    public class SoapSender    {        public virtual void SendSoapArgs<T>(T args)            where T : SoapArgs<T>        {        }    }

也很簡單對吧?邏輯上,這個函數(shù)可以接受前面兩個類的實(shí)例對吧?可實(shí)際上,下面第二行代碼會出編譯錯誤。

new SoapSender().SendSoapArgs(new GenericSoapArgs<int>());new SoapSender().SendSoapArgs(new DerivedGenericSoapArgs<int>());

錯誤信息是:

The type 'DerivedGenericSoapArgs<int>' cannot be used as type parameter 'T' in the generic type or method 'SoapSender.SendSoapArgs<T>(T)'. There is no implicit reference conversion from 'DerivedGenericSoapArgs<int>' to 'SoapArgs< DerivedGenericSoapArgs<int>>'.

解決辦法倒也算簡單,讓DerivedGenericSoapArgs自己再實(shí)現(xiàn)一遍SoapArgs接口就可以了——盡管它的父類已經(jīng)實(shí)現(xiàn)了。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 隆昌县| 娄底市| 安新县| 荆门市| 正定县| 肥城市| 西城区| 壤塘县| 涞水县| 阿克苏市| 海原县| 怀来县| 阳朔县| 黔西县| 蓬安县| 芮城县| 许昌市| 北辰区| 常宁市| 朝阳区| 土默特右旗| 石屏县| 邳州市| 静宁县| 东港市| 柳州市| 江川县| 乐亭县| 丹寨县| 醴陵市| 衡阳县| 怀化市| 衡南县| 石家庄市| 平乡县| 南昌县| 麻栗坡县| 贡觉县| 祁阳县| 黑河市| 科技|