2009-09-09 143 views
2

理論問題的種類。相當長的時間,如果你沒有理論的心情,可以隨意跳過。是否有可能在C#中爲泛型創建「此類型」?

想象一下,你有兩個類,一個從另一個繼承。基類是通用的,並且在關閉類型中必須返回該關閉類型的某個實例。

像這樣(注意:???文本):

public class Adapter<T> 
{ 
public virtual ??? DoSomething() 
{ 
    ... 
} 
} 

public class AdaptedString : Adapter<String> 
{ 
public override AdaptedString DoSomething() 
{ 
    ... 
} 
} 

,因爲沒有辦法來指代從一個泛型類型派生封閉式我不能這樣做。 (對於破碎的語言,抱歉,只是不知道如何表達它。)沒有設置關鍵字來代替???來指定此方法將返回將從此泛型類型派生的類型實例。

相反,我可以使用顯式傳遞類型名稱到泛型基地的解決方法。但它看起來多餘。

public class Adapter<TThis,T> 
{ 
public virtual TThis DoSomething() 
{ 
    ... 
} 
} 

public class AdaptedString : Adapter<AdaptedString,String> 
{ 
public override AdaptedString DoSomething() 
{ 
    ... 
} 
} 

如果在基類中我需要訪問TThis實例的成員,我要補充的約束。這一次,它看起來醜陋 - 注意約束:

public class Adapter<TThis,T> 
where TThis : Adapter<TThis, T> 
{ 
protected int _field; 

... 

public bool Compare(TThis obj) 
{ 
    return _field == obj._field; 
} 
} 

public class AdaptedString : Adapter<AdaptedString,String> 
{ 
... 
} 

是的,這是所有工作,但它會更好看,如果我可以簡單地使用一些關鍵字,而不是???在第一個代碼片段。類似於「thistype」。

您認爲它會起什麼作用?它有用嗎?或者,也許這只是簡單的愚蠢?

回答

7

沒有什麼,這使得此模式更容易,而事實上該模式是不是很防彈無論如何 - 因爲你可以有:

class TypeA : Adapter<TypeA, string> 

class TypeB : Adapter<TypeA, string> // Bug! 

這裏第二行是完全合法的 - TypeA是一個有效的類型參數對於TThis類型參數,即使它不是我們想要的。基本上,類型系統不會讓我們表達「T必須是這種類型」的概念。但是,我不同意那些認爲它是壞的或無用的模式的人。我發現它在Protocol Buffers有用(如果很複雜) - 這將是很多沒有它更糟。例如:

Foo foo = new Foo.Builder { Name="Jon" }.Build(); 

是行不通的,如果Foo.Build()不強類型返回Foo,即使在IBuilder<...>指定了Build方法。

這是值得避免的,如果你很容易可以只是因爲它變得如此複雜 - 但我認爲這是一個有用的模式知道。

+0

+1我站在更正:) –

+0

喬恩,在你的例子中的第二行只是不同的東西,不落入這種模式。如果有必要,可以通過現有的語法來實現。 我只是覺得這個語法讓我的例子更加複雜。在我們的代碼中發現錯誤後,我寫了這篇文章。前一段時間我最初編寫了這個基類,但我不得不重讀幾遍以再次抓握。難怪其他人介紹了一個bug。 – XOR

+0

@XOR:我的觀點是第二行是* legal *,但不受歡迎(在這種情況下)。我將編輯答案以使其更清楚。 –

4

你通常只是想指基類在這種情況下:

public class Adapter<T> { 
    public virtual Adapter<T> DoSomething(); 

試圖做你完成的事情違反了Liskov substitution principal

+1

它看起來像這裏是完美的答案:http://stackoverflow.com/questions/1400317 – dtb

+0

是的,但這不是相同的情況。他們不是從基類開始工作,而是從具體類型開始工作。 –

+0

不,裏德這不會工作,因爲我想在派生(封閉)類型的DoSomething返回AdapdedString,而不是它的基類型。 – XOR

-1

如果派生類中的繼承方法需要返回派生類型而不是基類型(稱爲covariant return type),則C#中已支持此方法。

+0

否,因爲C#不支持協變返回類型。 –

+0

(即使它確實如此,仍然不足以提供幫助。) –

+0

對不起,以爲它確實如此。 –

-1

我也無法找到一個有爭議的用例(雖然這是一個有趣的想法)。

你是否試圖改變你如何約束你可以使用的通用類型?這聽起來像你想假設一些基本功能,而不知道實際類型;這是接口爲。 where子句對於這些問題非常方便。

class Dictionary<K, V> 
where K : IComparable, IEnumerable 
where V : IMyInterface 
{ 
    public void Add(K key, V val) 
    { 
    } 
} 

上面的例子約束K(關鍵),因此它必須是具有可比性和可枚舉,和V必須實現您通過自己的接口所需的任何客戶的功能。

相關問題