【问题标题】:How to use value types in generics如何在泛型中使用值类型
【发布时间】:2012-07-21 08:50:00
【问题描述】:

我有以下代码:

public class Class1
{
    void ValueSpecific(string arg)
    {
        // do string stuff
    }
    void ValueSpecific(int arg)
    {
        // do int stuff
    }
    void ValueSpecific(float arg)
    {
        // do float stuff
    }
    void ValueGeneric(string arg)
    {
        // do stuff
        ValueSpecific(arg);
        // do more stuff
    }
    void ValueGeneric(int arg)
    {
        // do stuff
        ValueSpecific(arg);
        // do more stuff
    }
    void ValueGeneric(float arg)
    {
        // do stuff
        ValueSpecific(arg);
        // do more stuff
    }
    void Main(string s, int i, float f)
    {
        ValueGeneric(s);
        ValueGeneric(i);
        ValueGeneric(f);
    }
}

这可行,但 ValueGeneric 的所有三个重载的主体都是相同的。我想将它们合并为一种方法,如下所示:

void ValueGeneric<T>(T arg) where T: string, float, int
{
    // do stuff
    ValueSpecific(arg);
    // do more stuff
}

但这当然不是有效的 C#。 我能想到的最好的是:

void ValueGeneric(object arg)
{
    // Do stuff
    if (arg is int)
    {
        ValueSpecific((int)arg);
    }
    else if (arg is string)
    {
        ValueSpecific((string)arg);
    }
    else if (arg is float)
    {
        ValueSpecific((float)arg);
    }
    else
    {
        Debug.Assert(false, "Invalid type)
    }
    // Do more stuff
}

但这似乎很不雅。我会很感激任何建议。 (虽然我对任何解决方案都感兴趣,但 .NET3.5 支持的解决方案最好,因为我正在使用它。)

【问题讨论】:

  • 如果你真的想这样做,你就不得不求助于反射。
  • 扩展方法怎么样?
  • @JeffMercado 是对的。如果你想要优雅,你必须使用反射。

标签: c# .net


【解决方案1】:

假设您在所有重载之前和之后都在做相同的事情,您可以应用通常的方法来分解代码中的不同之处并将它们参数化。唯一改变的是传入的参数和您对该参数执行的操作。把它们都传进去。

static void ValueGeneric<T>(T arg, Action<T> action)
{
    // do stuff
    action(arg);
    // do more stuff
}

然后使用适当的操作调用泛型方法(您的ValueSpecific 重载会很好地自行解决)。

ValueGeneric(s, ValueSpecific);
ValueGeneric(i, ValueSpecific);
ValueGeneric(f, ValueSpecific);

【讨论】:

  • 我喜欢那个。谢谢。顺便说一句,一分钟前这里还有一大堆其他答案,包括一个来自 HatSoft 的使用“动态”的答案(它在 .NET 4 中有效),但它们都消失了。幸运的是,我抓住了 HatSoft 的解决方案。 HatSoft,你是把它删了,还是有人在管理这个页面?
  • @Dave。我删除了我的,因为这不是我永远承诺的解决方案。其他人可能已经效仿。 “动态”解决方案会起作用,但您最好使用特定方法来确保您在编译时发现问题,而不是冒运行时错误的风险。
【解决方案2】:

根据我对其他大型 .NET 项目的了解,您可以同时包含特定和通用重载。如果不存在特定的重载,他们将只使用通用版本:

void ValueGeneric(int i);
void ValueGeneric(string s);
void ValueGeneric(float f);
void ValueGeneric<T>(T t);

根据您发布的代码结构,您似乎想对ValueSpecific 的内容之前和之后的所有类型做一些事情,因此您可以将所有PreValueGenericPostValueGeneric 方法设为私有ValueGeneric重载在开头和结尾调用以避免重载之间的代码重复。

【讨论】:

    【解决方案3】:

    您是否考虑过为每种类型使用扩展方法?它可能是这种情况的替代方案。

    您可以定义一个类并定义该方法。喜欢:

    namespace ExtensionMethods
    {
        public static class Class1
        {
            static void ValueSpecific(this string arg)
            {
                // do string stuff
            }
            static void ValueSpecific(this int arg)
            {
                // do int stuff
            }  
        }
    }
    

    然后,当你想使用它们时,就这样做

    Int32 myIntVar = 20;
    myIntVar.ValueSpecific();
    String myStringVar = "hi",
    myStringVar.ValueSpecific();
    

    你必须添加

    using ExtensionMethods;
    

    只声明方法并使用它们。

    【讨论】:

    • 一个有趣的想法,但不幸的是在现实世界中 ValueSpecific 方法不是静态的,它们是类的非静态方法。它可以通过一些大量的重构来完成,但我认为它最终会变得更加不透明。
    • 是的,它们是静态的,但我认为作为替代发布很有趣。
    猜你喜欢
    • 2019-10-13
    • 2021-09-21
    • 2017-02-02
    • 2021-12-06
    • 1970-01-01
    • 1970-01-01
    • 2018-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多