1

I need to write an extension method in order to replace a char in a string and in a StringBuilder. I can write two extension methods like:

public static string ReplaceChar(this string value, string charToReplace)
{
    return value.Replace(charToReplace, "_");
}

public static StringBuilder ReplaceChar(this StringBuilder value, string charToReplace)
{
    return new StringBuilder (value.ToString().Replace(charToReplace, "_"));
}

But I don't know if there is the possibility to write a generic method like:

public static T ReplaceChar<T>(this T value, string charToReplace)
{
    return new T(value.ToString().Replace(charToReplace, "_"));
}

In this case I have an error: T does not have a new() constructor

Cap_72
  • 21
  • 1
  • 5
  • 1
    try public static T ReplaceChar(this T value, string charToReplace) Where T: new() – Harry Apr 13 '16 at 11:15
  • 2
    You should use `StringBuilder.Replace` instead of creating an intermediate string to do the replace on. If you do that there's no generic operation remaining since you are just relying on the existence of a method on the receiver. – Lee Apr 13 '16 at 11:19
  • 1
    @Harry - that won't work as the code is trying to call a parameterized constructor. The `new()` constraint requires the type to have parameterless constructor. – Sean Apr 13 '16 at 11:20
  • 1
    I'll second Lee's comment. Strings are immutable so `ReplaceChar` returning a new string is expected behavior. Most string builders methods however are called for their side-effects (modifying the string builder they're called on), so `ReplaceCharacter` returning a *new* string builder is definitively *not* what I would expect it to do. It should return the string builder it's called on instead. – Pieter Witvoet Apr 13 '16 at 11:24
  • @sean oh yea of course, you are correct. – Harry Apr 13 '16 at 11:25
  • if both string and stringbuilder has a common interface that defined the replace function then you could extend that, unfortunately as they don't you can't so your stuck with creating one for each type – MikeT Apr 13 '16 at 11:25
  • I agree with @PieterWitvoet. The point of `StringBuilder` methods returning a `StringBuilder` is to allow for method chaining. In you chain multiple `ReplaceChar` calls on a `StringBuilder` it would defeat the point of using a `StringBuilder` by creating a new `string` and `StringBuilder` in each call. – juharr Apr 13 '16 at 11:36
  • ps are you aware that string builder already defines a replace function that works inside itself with out having to create a new string builder? – MikeT Apr 13 '16 at 11:37
  • 1
    A generic method that is designed to work on only two concrete types is a bad idea. Generic methods should be... well, ...generic, that is, work with *any* type (in theory limitless) that complies with the supplied constraints. The correct solution here is to overload `ReplaceChar`. That said, I agree with Olivier, your `StringBuilder` extension method is awful. – InBetween Apr 13 '16 at 11:45

3 Answers3

4

it is a very bad idea. You want to use an immutable type and a mutable type in the same way. The sole role of a StringBuilder is to offer better speed performance for string operations. Your StringBuilder extension method is awful and useless.

  • Awful because it creates 2 objects and is against StringBuilder philosophy.
  • Useless because StringBuilder already has a Replace method
2

There are two problems with your approach. The one giving you the error is that T needs to have a new() constraint if you want to new it:

public static T ReplaceChar<T>(this T value, string charToReplace)
     where T : new()

The second problem is that the constraint only says it has a constructor without parameters, you can't call a constructor with parameters... so:

return new T(value.ToString().Replace(charToReplace, "_"));

Is just not possible, it's a limitation of generics (you can't make a constraint of new(string) or anything similar). Would probably be a nice feature and you can suggest it :-)

So about your specific question, it's not possible to do what you want: string and StringBuilder are two completely different types, which don't share any useful interface, and no useful constraint that may let you use both in a generic method (be it an extension method or not). You are down to implement both extension methods for this specific case.

About the question title ("Write an extension method for generic type"), yes, it's possible to have such an extension method with generics, and it'll work for all types that meet the constraints of T. It doesn't make much sense without specific constraints (like interfaces) since you won't be able to basically do anything with the object... and if you are not using constraints, you'd be better off making an extension method of object.

The only thing that comes to mind where this might be useful, is if trying to make an extension method of a type that requires the same type to be passed as an additional parameter... something like:

public static int Compare<T>(this T value, T value2)
    where T : IComparable
{
    return value.CompareTo(value2);
}

Where you want to make sure that the second parameter is of the same type that the extended object.

Jcl
  • 27,696
  • 5
  • 61
  • 92
  • Jcl are you tell me that there is the possibility to do it?...how? – Cap_72 Apr 13 '16 at 11:26
  • @Cap_72 no, exactly what you want, is not possible, since `string` and `StringBuilder` are two completely different and unrelated types, no useful constraints will match both. I'm saying it's possible to have extensions for generic types, not the exact one you want – Jcl Apr 13 '16 at 11:29
  • Sorry if I wasn't clear and let you the impression that it was possible. I've edited to add further comments – Jcl Apr 13 '16 at 11:36
0

Unfortunately, there is no simple way you can achieve this

You cannot use any constructor that takes parameters from generics. They are limited purely to "new T()'.

You can get around this using reflection, but it will render your code difficult to understand and prevent compile-time type checking.

Søren Debois
  • 5,598
  • 26
  • 48
user2216
  • 809
  • 1
  • 8
  • 24
  • I meant that you can try to use reflection to get constructor with parameter. Look [here](http://stackoverflow.com/questions/3255697/using-c-sharp-reflection-to-call-a-constructor) – user2216 Apr 13 '16 at 11:22
  • 1
    If you are going to do that, it doesn't make much sense to use generics... just make an extension of `object` – Jcl Apr 13 '16 at 11:23