Juraj Blaho
Juraj Blaho

Reputation: 13451

Passing generic argument to overloaded method

Is it possible to pass generic argument into overloaded method?

class Shop
{
  void CreateButton<T>(T itemToBuy)
  {
    var button = CreateButtonImpl();
    button.onClick.AddListener(() => Buy(itemToBuy));
  }

  void Buy(C c) {}
  void Buy(D d) {}
}

class C {}
class D {}

In the above code, there is an error that T cannot be converted to C. Is there any way to fix it?

Upvotes: 0

Views: 317

Answers (3)

Peeticus
Peeticus

Reputation: 63

I can't really test out the code without access to the CreateButtonImpl method, but I think if you push the generic type declaration up to the class level (away from method level), remove one of the buy methods, and replace the other with one that accepts a parameter of type T, you'll get what you want. Here's a sample that illustrates:

namespace EmptyConsole
{

    class Shop<T>
    {

        public void CreateButton(T itemToBuy)
        {
            var button = CreateButtonImpl();
            button.onClick.AddListener(() => Buy(itemToBuy));
        }

        void Buy(T itemToBuy) { }
    }

    class C { }
    class D { }

    class Program
    {
        static void Main(string[] args)
        {
            var shop = new Shop<C>();
            shop.CreateButton(new C());
        }
    }
}

It might be worth also having classes C and D implement the same interface (create a new interface that represents what they can do) and restricting the generic type parameter T to something that implements that shared interface. Here's a revised example that shows what that scenario might look like:

namespace EmptyConsole
{

    class Shop<T> where T : IPurchaseable
    {

        public void CreateButton(T itemToBuy)
        {
            var button = CreateButtonImpl();
            button.onClick.AddListener(() => Buy(itemToBuy));
        }

        void Buy(T itemToBuy) { }
    }

    interface IPurchaseable { }

    class C : IPurchaseable { }
    class D : IPurchaseable { }

    class Program
    {
        static void Main(string[] args)
        {
            var shop = new Shop<C>();
            shop.CreateButton(new C());
        }
    }
}

Upvotes: 0

Blindy
Blindy

Reputation: 67382

No, it's not possible. From the caller side you might know what you're passing in (though you might not just as well if you pass a base class), but from inside all you know is T and whatever restrictions you placed on it (none in this case).

To do what you want you need to get the run-time type of that T (T.GetType()) and compare it to the types of those other classes (typeof(C) and typeof(D) respectively), then do a cast and manually forward the parameter to the right function.

Upvotes: 1

Servy
Servy

Reputation: 203821

The method shouldn't be generic in the first place, because it can only support two specific types, rather than any type (making it actually generic in the general sense of the word).

Just have two overloads to Caller, one that accepts a C and one that accepts a D.

There is no way to solve this problem in a way that allows for static type checking. If you really have to do it, then the best that you can do is to check the type of the parameter (i.e. through is) and call each overload directly. You can let the compiler write that code for you by using dynamic, but then you still lose all of your static type safety, as well as take a fairly notable performance hit.

Upvotes: 1

Related Questions