代码之家  ›  专栏  ›  技术社区  ›  Tahir Hassan

C一般仿制药(一个严肃的问题)

  •  11
  • Tahir Hassan  · 技术社区  · 14 年前

    在C中,我试图编写代码,在这里我将创建一个func委托,它本身就是通用的。例如,以下(非泛型)委托正在返回任意字符串:

    Func<string> getString = () => "Hello!";
    

    另一方面,我想创建一个类似于泛型方法的泛型。例如,如果我希望一个通用的func返回类型t的默认值(t),我可以想象我编写的代码如下:

    Func<T><T> getDefaultObject = <T>() => default(T);
    

    那我就把它当作

    getDefaultObject<string>() 它将返回空值,如果我要写 getDefaultObject<int>() 将返回0。

    这个问题不仅仅是一个学术练习。我找到了很多地方可以使用这个,但是我不能正确地使用语法。这有可能吗?有没有提供这种功能的库?

    4 回复  |  直到 7 年前
        1
  •  4
  •   Benjamin Hodgson    7 年前

    尽管有人可能会发现 实际解决方法 像斯蒂芬·克利里的

    Func<T> CreateGetDefaultObject<T>() { return () => default(T); }
    

    在可以直接指定泛型的地方,从理论上讲,这是一个相当有趣的问题,C的当前类型系统无法解决这个问题。


    一种你称之为 本身是通用的 ,被称为 高等级类型 .

    请考虑以下示例(伪C):

    Tuple<int[], string[]> Test(Func<?> f) {
        return (f(1), f("Hello"));
    } 
    

    在您建议的系统中,一个呼叫可能如下所示:

    Test(x => new[] { x }); // Returns ({ 1 }, { "Hello" })
    

    但问题是:我们如何键入函数 Test 这是一个论点 f ? 显然地, f 每种类型的地图 T 数组 T[] 这种类型的。也许吧?

    Tuple<int[], string[]> Test<T>(Func<T, T[]> f) {
        return (f(1), f("Hello"));
    } 
    

    但是这个不行 . 我们不能参数化 试验 具有 任何特定 T ,因为 f 应该可以应用于 全部的 类型 T . 在这一点上,C型系统不能再进一步。

    我们需要的是一个符号

    Tuple<int[], string[]> Test(forall T : Func<T, T[]> f) {
        return (f(1), f("Hello"));
    } 
    

    在您的情况下,您可以键入

    forall T : Func<T> getDefaultValue = ...
    

    我所知道的唯一支持这种泛型的语言是haskell:

    test :: (forall t . t -> [t]) -> ([Int], [String])
    test f = (f 1, f "hello")
    

    在上看到这个haskellwiki条目 polymorphism 关于这个 forall 表示法。

        2
  •  8
  •   Blindy    14 年前

    你不能只根据返回值来重载任何东西,所以这包括变量。

    但是,您可以去掉该lambda表达式并编写一个实函数:

    T getDefaultObject<T>() { return default(T); }
    

    然后你想怎么称呼它:

    int i=getDefaultObject<int>();       // i=0
    string s=getDefaultObject<string>(); // s=null
    
        3
  •  0
  •   Stephen Cleary    14 年前

    这是不可能的,因为代表 实例 在C中,不能有泛型参数。最接近的方法是将类型对象作为常规参数传递并使用反射。:(

    在许多情况下,铸造 动态 帮助消除反射的痛苦,但是 动态 在创建新实例(如示例)时没有帮助。

        4
  •  -1
  •   Femaref    14 年前

    不能这样做,因为泛型类型参数必须在运行时已知。必须使用Activator类:

    Object o = Activator.CreateInstance(typeof(StringBuilder));

    你想做什么就做什么。您可以按以下方式编写:

    public T Default<T>()
    {
      return (T)Activator.CreateInstance(typeof(T));
    }
    

    编辑

    布林迪的解决方案更好。