关闭类型

时间:2010-07-20 19:36:38

标签: c# switch-statement

  

可能重复:
  Switch Case on type of object (C#)

我有一个方法签名,如下所示:

    public static TLocalType ToLocalType<TLocalType, TContract>(TContract contract)
    {

我希望能够根据TContract的实际类型做不同的事情(即调用不同的方法)。有没有办法做这样的事情?

        switch (TContract)
        {
             case SomeTypeHere:

7 个答案:

答案 0 :(得分:3)

不幸的是,你能做的最好的就是

switch(typeof(TContract).ToString()) 

请注意,这包括名称空间。 另请注意,它将忽略继承和接口。

Peter Hallam explains why the language doesn't support this

答案 1 :(得分:3)

这是一个经常被要求的功能,我们不打算这样做。有关详细信息,请参阅Peter Hallam关于此主题的文章。

http://blogs.msdn.com/b/peterhal/archive/2005/07/05/435760.aspx

请注意如果您要打开通用类型,那么您可能在某处存在设计缺陷。泛型的全部意义在于它们是泛型;你不应该关心实际类型是什么。

答案 2 :(得分:2)

您无法打开Type对象,但可以打开它的名称:

switch( typeof(TContract).Name )
{
   case "Namespace.SomeTypeName": ...
}

但是,一般情况下,这很少被证明是一个很好的设计选择。最好传入委托或实现接口的对象(甚至是泛型类型参数)来定义处理不同类型的“策略”。

这是关于设计和编写泛型类型的常见问题 - 即基于泛型类型参数的类型执行完全不同的操作的能力。 我倾向于认为这是一种代码气味,你可能没有使用泛型,因为它们是预期的,你的设计是“反对谷物”,可以这么说

但是,在某些情况下,确实需要执行因类型不同的处理,在这种情况下,传递一个单独的类型(作为另一个通用参数的构造函数)允许您将不同的关注点分成“策略”,更具可扩展性,更清晰,更少与通用类的实现耦合。一个例子可能是:

interface IOperation<T>
{
    T Add( T first, T second );
}

public class Calculator<T,TOp>
   where TOp : IOperation<T>, new()
{
    private readonly TOp m_Op = new TOp();

    public T Sum( IEnumerable<T> values )
    {
        T accum = default(T);
        foreach( var val in values )
            accum = m_Op( accum, val );
        return accum;
    }
}

现在,您可以编写适用于不同类型的IOperation<T>的不同实现(整数,浮点数,复数,矩阵等)。然后,通用类Calculator<T,TOp>将与按类型不同的操作分开,但可以根据需要自由组合它们。

在.NET 4.0中,可以使用dynamic来分派一个或多个专用于某些类型的方法的重载。这种方法虽然更简单,但却会导致在运行时基本上调用编译器以确定要调用哪个方法的性能损失。尽管如此,DLR在呼叫站点缓存此信息方面做得相当不错,如果您多次调用该方法,可以分摊成本。

答案 3 :(得分:2)

如何在这里使用多态?我无法说出您的确切情况,但通常情况下,当您想要打开对象的类型时,这表明您可能需要考虑多态解决方案。

答案 4 :(得分:0)

switch语句只接受数字和字符串值,这意味着您不能使用Type值。您可以关闭该类型的ToString()值,但这样会尽可能接近。我建议改为使用enum

答案 5 :(得分:0)

请参阅这篇文章,了解为什么这是不可能的。

http://blogs.msdn.com/b/peterhal/archive/2005/07/05/435760.aspx

答案 6 :(得分:0)

Switch仅适用于字符串和其他基元。

您必须执行以下操作,您可以在其中关闭类型的字符串名称:

switch (typeof(T).FullName)
{
  case "System.Int32":
    Console.WriteLine("it's an int");
    break;
  case "System.String":
    Console.WriteLine("it's a string");
    break;
  default:
    Console.WriteLine("not sure");
    break;
}