Extend the primitive data types with custom methods

MikeyJY

Member
Joined
Sep 19, 2021
Messages
11
Programming Experience
5-10
Is it possible to make a custom method that is contained in an array type? For example:

C#:
int[,] array2D = new int[4,4];
array2D.customMethod();

And in this case the method to be accessible just for instances of int[,]
And the second question is it possible to make those methods static to be used from the data type:
C#:
int.method();

or at least from the corresponding wrapper classes:
I:
Int32.method();
 
what causes this:

C#:
namespace ExtensionMethods
{
    public static class MyExtensions
    {
        public static int WordCount(this String str)
        {
            return str.Split(new char[] { ' ', '.', '?' },
                             StringSplitOptions.RemoveEmptyEntries).Length;
        }
    }
}
What causes the WorldCount method to be called str.WorldCount and not WorldCount(str)
?
 
From the same link above:
Extension methods are defined as static methods but are called by using instance method syntax. Their first parameter specifies which type the method operates on. The parameter is preceded by the this modifier. Extension methods are only in scope when you explicitly import the namespace into your source code with a using directive.
Emphasis mine.

That is all compiler magic, though. In the end, the compiler generates code that is effectively MyEntensions.Word count(str);
 
Note that extension methods are called as though they are instance methods but they are not instance methods. You can also call an extension method like you would any other static method. It is still declared externally to the type it's being called on so it still doesn't have access to private members of that type. Extension methods exist as a convenience but they are not magic. They were added as a language feature to support LINQ, i.e. methods like Enumerable.Select and Enumerable.Where are extension methods on the IEnumerable<T> interface. They turned out to be rather useful and make the calling of many methods more natural, so they have found much use beyond LINQ.

Also, Int32 is not a "wrapper class" for the int data type. Int32 is a structure, for one thing. Also, Int32 is what is actually used whenever you use int in code. int is a language keyword that is simply an alias for the Int32 structure. It's possible that, in a future version of C#, they would change the implementation such that int became an alias for the Int64 structure while long became an alias for a new Int128 structure. I'm fairly confident that that won't happen, but it theoretically could. Native data types like int have no implementation of their own. They are just placeholders for whatever .NET data type the language designers chose to use. Similarly, the string data type is implemented using the String class, etc. You can basically consider the language keywords and the corresponding .NET types as being interchangeable and completely equivalent, as they will generate exactly the same CIL when compiled.
 
For the record, when I declare extension methods, I always declare a class named SomeTypeExtensions where SomeType is the type extended by the methods in that class. That means that each and every method in such a class extends the same type and, if I want to extend two different types, I declare two different classes for those extension methods. You may choose to do things differently but I think that that is a good way to keep things clear and easily understandable. In your case, you can't use 2dIntArrayExtensions because you cannot begin an identifier with a digit. That means either prepending an underscore or using a slightly worse name like Int2dArrayExtensions.
 
In general, I also do per type extension classes. As mentioned above, it makes finding stuff easier. Occasionally, I have operation specific extension classes that can be applied to multiple types either by virtue of generics; or simply that kind of operation can be applied to different specific types, but the use of generics would not be appropriate.
 
Also, Int32 is not a "wrapper class" for the int data type.
I believed that they are wrappers similar to java where int is a type and the Integer is wrapper or float and Float, however I don't understand what the wrapper term mean in this case. For example java doesn't treat the string as a type since you don't declare with string you use String which I think it is a class since the IDEs don't recognize it as a keyword similar to int.
 
The term "wrapper" indicates that one type is conceptually wrapped around another. Practically, that means that you don't access the functionality of the wrapped class directly, but rather access the functionality of the wrapper class, which then accesses the functionality of the wrapped class. This is generally done to provide a friendlier interface to that functionality. I don't use Java so I don't know how things work there but, in C#, .NET types like Int32 do not wrap C# data types like int. You can think of the C# data types as being conceptual rather than real. int, long and other C# data types are really just ideas. They are not actually implemented in the language itself. The ideas they represent have to be implemented by .NET types. int is currently implemented by the Int32 structure, so when you use int in code, the members you see are members of the Int32 structure. If the language authors decided to implement that data type with a different .NET type then you would see members of that new type instead. There is no wrapping of one type by another because there's nothing to wrap. The int data type has no functionality of its own.
 
This may help provide some background to the discussion:
 
What we say vs what we mean:
C#:
int test = 0;
Debug.WriteLine(test.GetType());

//output: System.Int32
 
Back
Top Bottom