2009-09-09 139 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必须实现您通过自己的接口所需的任何客户的功能。

相关问题