3

I'm trying to create an extension method that takes a Func as a parameter but I'm getting an error. Here's what I got:

public static class MyExtensions
{
    public static TResult ModifyString<T, TResult>(this string s, Func<T, TResult> f)
    {
        return f(s);
    }
}

on the return f(s); line I get an error: Error CS1503 Argument 1: cannot convert from 'string' to 'T'

How can I specify a generic lambda Func with a generic parameter T and a generic return type TResult?

Joels Elf
  • 714
  • 6
  • 10
  • 2
    You specified the lambda correctly. The problem is that its parameter is type `T` and you are passing it a string, but the compiler doesn't have any general way to convert string to "absolutely any type at all", which is what `T` can be. – 15ee8f99-57ff-4f92-890c-b56153 May 18 '18 at 20:30
  • Replace T with a string class or provide a concept like "where T: string" – Kirill Korolev May 18 '18 at 20:31
  • 3
    Clearly, you want `f` to be a function that acts on a string. What you want would appear to be `TResult ModifyString(this string s, Func f) => f(s);`. Either that, or `TResult ModifyString(this T t, Func f) => f(t);` – 15ee8f99-57ff-4f92-890c-b56153 May 18 '18 at 20:33
  • @KirillKorolev: You can't do `where T : sealedtype`. `where T : string` is the same as "T must always be string", so why have T at all? – Eric Lippert May 18 '18 at 21:53
  • @EricLippert Yeah, that's why I was curious, why does he need a template parameter. – Kirill Korolev May 18 '18 at 21:57
  • @KirillKorolev I was asked how to do this in a phone interview, but I may have misremembered the exact question. I thought the parameter to the lambda had to be generic (I could've sworn the interviewer wrote something like Func), but I must've remembered wrong. – Joels Elf May 18 '18 at 22:00

2 Answers2

2

The problem is you are passing "s" - a string into the func which is declared as taking in type "T".

Change the func to take in a string instead of T, and return a string to make this code work with strings.

public static class MyExtensions
{
    public static string ModifyString(this string s, Func<string, string> f)
    {
        return f(s);
    }
}

Assuming you just want a string result.

gmn
  • 4,199
  • 4
  • 24
  • 46
  • I can't imagine what "modify string" means other than this ([for whatever my imagination is worth](http://www.shakespeare-online.com/quickquotes/quickquotehamletdreamt.html)). – 15ee8f99-57ff-4f92-890c-b56153 May 18 '18 at 20:38
  • 1
    @EdPlunkett me neither, but it is still an assumption – gmn May 18 '18 at 20:41
  • @EdPlunkett It's just a pointless example. I was asked if I could create an extension method (nope) that takes in a string (I think) and a generic lambda that operates on the string and returns something. – Joels Elf May 18 '18 at 22:06
  • @JoelsElf Ok. Func is generic and this answer uses it. If you’re passing it a string, you *must* provide string for that type parameter (or constrain it to be string or a subclass of string — but string is a sealed class, so there can’t be a subclass). I wouldn’t call it pointless though — you’ve learned something. – 15ee8f99-57ff-4f92-890c-b56153 May 18 '18 at 22:21
  • @Joelself I actually almost created a version of this answer as I now know you want, but went with string, string as I thought it was more likely from the question. Ah well, still not pointless though, with this sort of stuff its using the defined types consistently that matters – gmn May 18 '18 at 23:25
2

As the other answer and comments suggest, you already know the parameter type T, so you only need to specify TResult:

public static TResult ModifyString<TResult>(this string s, Func<string, TResult> f)
{
    return f(s);
}

or consistently pass T:

public static TResult Modify<T, TResult>(this T s, Func<T, TResult> f)
{
    return f(s);
}
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • For some reason I thought my interviewer had the extension method be specifically for a string (or some other concrete type) while the lambda had to take a generic parameter, but now I think I remembered that wrong and the lambda must take a string specifically. Anyways, thanks! – Joels Elf May 18 '18 at 22:03