代码之家  ›  专栏  ›  技术社区  ›  BartoszKP

如何使用不带泛型约束的类型参数调用具有泛型约束的方法?

  •  3
  • BartoszKP  · 技术社区  · 7 年前

    public void ExampleMethod<T>(T x) where T : struct // or new()
    {
        // example usage, similar to what's actually happening
        var z = (T)Enum.Parse(typeof(T), privateFieldOfTypeString);
    
        // do something depending on values of x and z
        // possibly using other methods that require them being enums
    
        // or in case of the new() constraint:
        // var t = new T() and do something together with x
    }
    

    我想使用它如下:

    public void CallerMethod<S>(S y)
    {
        if (typeof(S).IsEnum) // or some other invariant meaning that `S` is "new()able"
        {
            ExampleMethod(y); // won't compile
        }
    }
    

    所以,在运行期间,我知道这一点 S ExampleMethod<T> . 我知道可以用反射来称呼它,大致如下:

    this
        .GetType()
        .GetMethod(nameof(ExampleMethod<object>))
        .MakeGenericMethod(typeof(S))
        .Invoke(this, new object[] { y });
    

    不经思考就可以吗?

    这是一个来自真实示例的简化代码,显然我无法控制这些方法的签名,因此答案是“将约束添加到 CallerMethod 和“从中删除约束” ExampleMethod

    是的,整个事情应该重新设计,这样整个问题就不会出现了。但在现实生活中,“整件事”往往太大,太耦合,太冒险,无法重写。一些需求以一种意想不到的方式发生了变化——因此出现了明显的代码气味,我正试图通过将其隐藏在一个看起来很恶心的地方来尽量减少这种气味。

    4 回复  |  直到 7 年前
        1
  •  3
  •   Dirk    7 年前

    你可以用 dynamic :

    if (typeof(S).IsEnum)
    {
        ExampleMethod((dynamic)y);
    }
    
        2
  •  2
  •   qujck Steven    7 年前

    CallerMethod ExampleMethod

    CallerMethod(Enum1 value) { ExampleMethod(value); }
    CallerMethod(Enum2 value) { ExampleMethod(value); }
    CallerMethod(Enum3 value) { ExampleMethod(value); }
    

    如果有大量正在增长的类型需要 呼叫者方法 你可以写一封信 T4 template 产生 partial

        3
  •  1
  •   Nkosi    7 年前

    如果枚举类型是已知的,那么一种可能(尽管冗长)是转换为已知类型。

    比如说作为一个起点,,

    public void CallerMethod<S>(S y) {
        if (typeof(S).IsEnum) {
            if (y is KnownEnum) {
                var z = (KnownEnum)Enum.Parse(typeof(S), y.ToString());
                ExampleMethod(z);
            }
            if (y is KnownEnum2) {
                var z = (KnownEnum2)Enum.Parse(typeof(S), y.ToString());
                ExampleMethod(z);
            }
            //...
        }
    }
    
        4
  •  -3
  •   John Wu    7 年前

    在您的特定情况下,您可以强制转换为int。

    public void CallerMethod<S>(S y)
    {
        if (typeof(S).IsEnum)
        {
            ExampleMethod((int)y);
        }
    }