PowerApp101
PowerApp101

Reputation: 1826

C# Func<> delegate argument conversion error

When I run this program I get two errors on the line containing fn(3,4)

Argument 1: cannot convert from 'int' to T

Argument 2: cannot convert from 'int' to T

I thought type T would be int, as specified by the lambda. But if so then why the conversion errors? Am I misunderstanding something?

class Program
{
    static void DoStuff<T>(Func<T, T, T> fn)
    {
        Console.WriteLine(fn(3, 4));
    }

    static void Main()
    {
        DoStuff((int x, int y) => x + y);
    }
}

This works, if I change the parameters to accept the ints as arguments:

class Program
{
    static void DoStuff<T>(T x, T y, Func<T, T, T> fn)
    {
        Console.WriteLine(fn(x, y));
    }

    static void Main()
    {
        DoStuff(3, 4, (int x, int y) => x + y);
    }
}

I come from a C++ background, so trying to get my head around what works and what doesn't in C#

Upvotes: 2

Views: 113

Answers (2)

Thomas Levesque
Thomas Levesque

Reputation: 292345

Inside the DoStuff<T> method, the actual type of T is unknown; your code passes ints to the function, assuming that T is int, but T could actually be anything, like string, so you would be passing ints to a function that accepts only strings.


RE "I come from a C++ background, so trying to get my head around what works and what doesn't in C#":

C# generics look similar to C++ templates, but they're actually quite different.

  • In C++, templates are instantiated at compile time based on usage; if you use the template method with 3 different types for T, the compiler will generate 3 different methods. The body of the template method doesn't have to be valid for any T, as long as it's valid for the actual usage cases. (sorry if my explanation isn't perfectly accurate; I don't know C++ very well)

  • In C#, there is no compile-time generation based on usage; the compiler only generates 1 generic method, and the actual runtime method for a given T is generated by the runtime. To ensure this will work, the C# compiler must ensure that the method body will be valid for any T (or if you specified constraints for T, any T that matches the constraints). That's why you're getting an error in your first snippet: the body of the generic method would only be valid if T were int.

I suggest you read the answers to this question for a more detailed explanation.

Upvotes: 8

Henrik
Henrik

Reputation: 23324

No need to use generics here. Change

static void DoStuff<T>(Func<T, T, T> fn)

to

static void DoStuff(Func<int, int, int> fn)

Upvotes: 1

Related Questions