0xFF
0xFF

Reputation: 4178

C# method resolution on generic type

I have a method that I overload on a concrete type and tag for compile time failure on generic types (using [ObsoleteAttribute]).

The reason of doing do is to make sure any caller to the method specializes it for the target type. There is no way to change the actual types or their hierarchy; so I need to use have ad-hoc methods to achieve this goal (static void CustomMethod below).

Here is a sample code:

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");
    }
}

This fails with Error CS0619 'Program.CustomMethod<T>(T)' is obsolete: 'Unknown type'

This is easily achievable with C++ templates since the compiler only resolves invocation to the actual instantiated type and not any generic type T

Is there any "compile time" way to make the Invoke<T>() work?

Note: not looking for solutions using C# dynamic or reflection.

Upvotes: 2

Views: 123

Answers (1)

Eren Ers&#246;nmez
Eren Ers&#246;nmez

Reputation: 39085

Within the constraints you outlined, you really don't have any options other than creating separate Invoke overloads for each type you want a CustomMethod for.

Assuming Invoke does more than simply calling CustomMethod, you can avoid repeating that common code by creating child classes that wrap the CustomMethod, and handling the common stuff in the base class:

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");
    }
}

Upvotes: 1

Related Questions