【问题标题】:C# Is there any better way to use Switch-Case / If-Else on generic typesC# 有没有更好的方法在泛型类型上使用 Switch-Case / If-Else
【发布时间】:2019-12-29 12:58:59
【问题描述】:

我目前正在尝试对泛型类型进行一些转换。 所以基本思想是有一个方法接受泛型类型,并根据传入的类型做不同的事情。

为简单起见,我将仅展示floatbooldefault 的用法

设置看起来像这样(其中T 是类本身定义的泛型类型):

protected T DoStuff(T value)
{
   switch (value) {
      case float floatValue:
         float result = DoFloatStuff(floatValue);
         switch (result) {
            case T output:
               return output;
         }
      case bool boolValue:
         bool result = DoBoolStuff(boolValue);
         switch (result) {
            case T output:
               return output;
         }
      default:
         // return value;
         DoRealGenericStuff(value) // Edited, since I just want to sort out some special cases
   }
}

其中 DoFloatStuffDoBoolStuff 只是分别具有 1 个参数和其类型的返回类型的方法。

如果我不那样做(我之前尝试过一些typeof() 转换),编译器总是抱怨它不能从T 转换为float,反之亦然,即使我确定这会一些 Case-Switch / If-Else 语句就是这种情况。

有人知道更好的方法吗?

提前致谢, 两线

编辑: 由于很多人都说了同样的话,我要么根本不应该在这种情况下使用泛型,要么我的方法本身需要更通用。 我的问题是我需要使用第 3 方方法来处理我正在检查的特殊情况(在本例中为 floatbool 类型)。对于默认情况,我已经以通用方式处理了所有内容。但是对于某些已定义的类型,我就是不能这样做。

所以要更详细地说明为什么会这样: 我目前正在为“Unity Engine”开发插件。 Unity 内置了显示类型的方法(所有原始类型和一些 Unity 特定类型)。我有一个通用的 Wrapper 类,它应该能够包含任何类型。但是,当我想在 Unity Editor 提供的 GUI 中显示该包装器的内容时​​,我必须使用内置方法来显示原语(类似于UnityEditor.EditrGUI.FloatField())。没有这些方法,我永远无法显示任何东西。 然后可以以更通用的方式显示可以分解为这些类型的任何其他内容。

【问题讨论】:

  • 如果DoFloatStuffDoBoolStuff 如此不同以至于它们不能被“泛化”,那么你就没有使用泛型。放弃吧,拥有object DoStuff(object value)
  • @Dialectus 如果您不知道对象的类型,那应该是唯一的选择。如果编译器可以在编译时找出类型,那么他应该使用方法重载,而不是泛型,而且绝对不是object

标签: c# if-statement generics casting switch-statement


【解决方案1】:

因此,基本想法是有一个方法接受泛型类型,并根据传入的类型执行不同的操作。

这是错误的想法。这不是应该使用泛型的方式。在这种情况下,您应该使用方法重载为每种类型分别创建DoStuff

float DoStuff(float value) {/* float implementation here */}
bool DoStuff(bool value) {/* bool implementation here */}
...

泛型的意义在于使您能够编写在不同类型上运行相同的代码 - 所以它应该用于类型本身与代码无关的情况(如在任何泛型集合中)或可以执行使用接口或基类,所有可接受的类型都实现(或继承)。此时,泛型通常仅在您希望方法返回接口(或基类)的特定实现时才需要。

【讨论】:

  • 嘿,非常感谢您的评论。首先,我编辑了最初的帖子以使自己更加清晰,因为我没有很好地解释所有内容。因为我当然想以通用的方式处理大多数情况,所以我需要整理一些特殊情况。但是,是的,你的“这不是泛型的想法”真的让我思考。而且我应该能够以通用方式使用方法DoStuff,然后用我的特殊情况继承并以正确的方式覆盖该方法,因为我不再需要进行任何类型检查。非常感谢! :)
  • 很高兴为您提供帮助 :-)
【解决方案2】:

让编译器帮你整理一下:

protected void DoStuff(float v){}
protected void DoStuff(int v){}
// and so on
//and finally the default:
protected void DoStuff(object v){}

public void Work(T value)
{
    DoStuff(value)
}

【讨论】:

    【解决方案3】:

    这不是简短的答案,但它是正确的方法(根据许多标准)。可能会有一个简短的答案,但如果我是你,我不会打扰。

    这是工厂模式的味道。顾名思义,泛型应该是泛型的并且与类型无关,如果你可以这样做的话。

    interface IDoStuffer<T>
    {
        T DoStuff(T value)
    }
    
    class DoStuffFloat : IDoStuff<float>
    {
        public float DoStuff(float value)
        {
            //Do your float stuff
        }
    }
    
    class DoStuffBool : IDoStuff<bool>
    {
        public bool DoStuff(bool value)
        {
            //Do your bool stuff
        }
    }
    

    然后你可以让工厂给你一个正确的实现

    class DoStuffFactory
    {
        public IDoStuff<T> GetDoStuff<T>()
        {
            if(typeof(T) == typeof(float))
                return new DoStuffFloat();
            //And other types
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多