Is there a way to write an Extension Method that applies to multiple types?
Asked Answered
H

2

8

I'm trying to write an extension method that will add the function HasFactor to the class int in C#. This works wonderfully, like so:

static class ExtendInt
{
    public static bool HasFactor(this int source, int factor)
    {
        return (source % factor == 0);
    }
}

class Program
{
    static void Main()
    {
        int i = 50;
        int f = 2;
        bool b = i.HasFactor(f);
        Console.WriteLine("Is {0} a factor of {1}? {2}",f,i,b);
        Console.ReadLine();
     }
}

This works great because variable i in the Main() method above is declared as an int. However, if i is declared as an Int16 or an Int64, the extension method does not show up unless it is explicitly cast as an int or Int32.

I now would like to apply the same HasFactor method to Int16 and Int64. However, I'd rather not write separate extension methods for each type of int. I could write a single method for Int64 and then explicitly cast everything as an Int64 or long in order for the extension method to appear.

Ideally, I'd prefer to have the same extension method apply to all three types without having to copy and paste a lot of code.

Is this even possible in C#? If not, is there a recommended best-practice for this type of situation?

Hifalutin answered 1/1, 2010 at 23:41 Comment(1)
Based on the input of Eilon and Marc Gravell, I think I'm going to create one extension method for type Int64. This should work for what I'm doing.Hifalutin
R
5

No, this is not possible in C#. You'll have to create one extension method for each type. The closest is to have an extension method that operates on an interface, but in this case there is no INumeric interface or anything similar that is implemented by the various numeric types.

Rahmann answered 1/1, 2010 at 23:43 Comment(4)
Actually it is possible by some convoluted usage of Expression Trees (and/or dynamics if you're in .NET 4.0) - Check out Marc Gravel's answer to another SO question here: #1987636, and his MiscUtil library.Wolof
Well, the operators (% etc) can use this - but not the extension method code. So I think (+1) that Eilon has the truth of it. A number of very similar overloads are in the future, I suspect.Bombacaceous
That's interesting. I'd be interested to know if dynamic (or some other .NET 4.0 feature) could be used to limit an extension method to specific types. Has this been done? (Perhaps this should be a separate SO question).Hifalutin
That's definitely an interesting idea. Though, I think even with dynamic, you'd want the type to implement IDynamicObject, which is of course not an option here since you don't own the types in question (int, long, etc.).Rahmann
S
0

Yes, this is possible using generics and constraints.

public static class ExtendInt
{
    public static bool HasFactor<T>(this T source, int factor) where T : IBinaryInteger<T>
    {
        return (Convert.ToInt64(source) % factor == 0);
    }
}

Some usage examples:

UInt64 u = 184467440737095568;
if (u.HasFactor(2)) // true

short s = 9;
if (s.HasFactor(3)) // true

double d = 3.36;
if (d.HasFactor(1)) // does not compile

dynamic x = 9.3;
if (x.HasFactor(8)) // throws a runtime error

Generics allow us to write a single method that works on multiple types. In your case, we need to restrict the types we can act on to whole numbers. For this we can use IBinaryInteger as a constraint. This extension method will work on the following types:

  1. System.Byte
  2. System.Char
  3. System.Int16
  4. System.Int32
  5. System.Int64
  6. System.SByte
  7. System.UInt16
  8. System.UInt32
  9. System.UInt64

I hope this helps whoever stumbles across this someday. Happy coding :)

Scrivener answered 24/9, 2024 at 22:11 Comment(1)
Could someone kindly explain why I got downvoted? I don't mind the downvote itself, but if my answer is incorrect or incomplete in some way, I'd like to know its shortcomings so I can learn from my mistakes. Thank you.Scrivener

© 2022 - 2025 — McMap. All rights reserved.