泛型类型的C#方法解析

时间:2017-03-09 22:18:33

标签: c# generics

我有一个方法,我在具体类型和标记上重载,以便在泛型类型上使用[ObsoleteAttribute])编译时失败。

这样做的原因是确保该方法的任何调用者都将其专门用于目标类型。无法改变实际类型或层次结构;所以我需要使用ad-hoc方法来实现这个目标(下面static void CustomMethod)。

以下是示例代码:

class Program
{
    class MyClass { }

    static void CustomMethod(MyClass m)
    {
        Console.WriteLine("m");
    }

    [ObsoleteAttribute("Unknown type", true)]
    static void CustomMethod<T>(T m)
    {
        ;
    }

    static void Invoke<T>(T input)
    {
        CustomMethod(input);
    }


    static void Main(string[] args)
    {
        // This should compile ok
        MyClass m = new MyClass();
        Invoke(m);

        // This should fail compilation
        Invoke("no CustomMethod() defined for me");
    }
}

此操作因Error CS0619 'Program.CustomMethod<T>(T)' is obsolete: 'Unknown type'

而失败

使用C ++模板很容易实现这一点,因为编译器只将调用解析为实际的实例化类型而不是任何泛型类型T

是否有任何“编译时”方式使Invoke<T>()工作?

注意:不使用C#dynamic或反射来寻找解决方案。

1 个答案:

答案 0 :(得分:1)

在您列出的限制条件中,除了为您想要Invoke的每种类型创建单独的CustomMethod重载之外,您实际上没有任何其他选项。

假设Invoke不只是简单地调用CustomMethod,您可以通过创建包装CustomMethod的子类并处理基类中的常见内容来避免重复该公共代码:

class Program
{
    class MyClass { }
    class MyClass2 { }

    // wrapper classes for CustomMethod for each type
    class MyClassStrategy : Strategy<MyClass>
    {
        protected override void CustomMethod(MyClass t)
        {
            Console.WriteLine("MyClass");
        }
    }
    class MyClass2Strategy : Strategy<MyClass2>
    {
        protected override void CustomMethod(MyClass2 t)
        {
            Console.WriteLine("MyClass2");
        }
    }

    // base class for doing "common stuff"
    abstract class Strategy<T>
    {
        protected abstract void CustomMethod(T t);
        public virtual void Run(T t)
        {
            // do common stuff... 
            CustomMethod(t);
            // do more common stuff...
        }
    }

    // create an Invoke overload for each wrapper class
    static void Invoke(MyClass m) { new MyClassStrategy().Run(m); }
    static void Invoke(MyClass2 m2) { new MyClass2Strategy().Run(m2); }

    static void Main(string[] args)
    {
        // These compile OK:
        MyClass m = new MyClass();
        Invoke(m);

        MyClass2 m2 = new MyClass2();
        Invoke(m2);

        // This doesn't compile: 
        // (obviously, there are no Invoke overloads that take a string)
        Invoke("sdfdsff");
    }
}