Extension methods on a struct

24,866

Solution 1

Yes, you can add extension methods on structs. As per the definition of extension method, you can easily achieve it. Below is example of extension method on int

namespace ExtensionMethods
{
    public static class IntExtensions
     {
        public static bool IsGreaterEqualThan(this int i, int value)
        {
            return i >= value;
        }
    }
}

Solution 2

It is possible to add extension methods to structures, but there is an important caveat. Normal struct methods methods accept this as a ref parameter, but C# will not allow the definition of extension methods which do so. While struct methods which mutate this can be somewhat dangerous (since the compiler will allow struct methods to be invoked on read-only structures, but pass this by value), they can also at times be useful if one is careful to ensure that they are only used in appropriate contexts.

Incidentally, vb.net does allow extension methods to accept this as a ByRef parameter, whether it is a class, struct, or an unknown-category generic. This can be helpful in some cases where interfaces may be implemented by structures. For example, if one attempts to invoke on a variable of type List<string>.Enumerator an extension method which takes a this parameter of type IEnumerator<string>, or takes by value a this parameter of a generic constrained to IEnumerator<string>, and if the method tries to advance the enumerator, any advancement will be undone when the method returns. An extension method which takes a constrained generic by reference, however, (possible in vb.net) will behave as it should.

Solution 3

For future Googlers (and Bingers), here's some code to extend a struct. This example turns the value into a double type.

public static class ExtensionMethods {

   public static double ToDouble<T>(this T value) where T : struct {
      return Convert.ToDouble(value);
   }
}

After this you can use ToDouble() like you use ToString(). Be careful on conversion items like overflows.

Solution 4

Yes, you can define an extension method on a struct/value type. However, they do not have the same behavior as extension methods on reference types.

For example, the GetA() extension method in the following C# code receives a copy of the struct, not a reference to the struct. This means that a C# extension method on a struct can't modify the original struct contents.

public static class TestStructExtensionMethods {
    public struct FooStruct {
        public int a;
    }
    public static int GetA(this FooStruct st) {
        return st.a;
    }
}

In order to modify the struct contents, the struct paramater needs to be declared as "ref". However, "this ref" is not allowed in C#. The best we can do is a static non-extension method like:

// this works, but is inefficient, because it copies the whole FooStruct
// just to return a
public static int GetA(ref FooStruct st) {
    return st.a;
}

In VB.NET, you can create this as a ByRef struct extension method, so it could modify the original struct:

' This is efficient, because it is handed a reference to the struct
<Extension()> _ 
Public Sub GetA(ByRef [me] As FooStruct) As Integer
    Return [me].a
End Sub

' It is possible to change the struct fields, because we have a ref
<Extension()> _ 
Public Sub SetA(ByRef [me] As FooStruct, newval As Integer) 
    [me].a = newval
End Sub
Share:
24,866
Ghyath Serhal
Author by

Ghyath Serhal

Updated on December 23, 2020

Comments

  • Ghyath Serhal
    Ghyath Serhal over 3 years

    Can you add extension methods to a struct?

  • MichaelTaylor3D
    MichaelTaylor3D over 11 years
    So what might be an example of using one in C#? public static Rect CreateRectFromPercents(this Rect rect) for example does not work.
  • supercat
    supercat over 11 years
    @MichaelTaylor3D: What is Rect? Do you mean System.Drawing.Rectangle or some custom type?
  • MichaelTaylor3D
    MichaelTaylor3D over 11 years
    its a struct that is part of my api im using. I was just using it as an example. The api blocks me from modifying it directly so I was hoping to use an extension method. Ive read that its possible for structs but i havnt seen an example yet. Your explanation is the closest i can find.
  • supercat
    supercat over 11 years
    One could write an extension method WithHeight which would take a Rect and return a new one which was identical except for the Height parameter. Out of curiosity, does the API gain anything by obstructing convenient access to the struct fields? I find peevish the notion that people should treat structs as "pretend classes", rather than recognizing that they are a different type of entity which should be approached differently. While very few classes should expose any fields publicly, I'd suggest that the vast majority of struct types should expose all fields publicly.
  • supercat
    supercat over 11 years
    @MichaelTaylor3D: To be sure, exposing public fields would make more apparent the fact that structs don't behave like class objects, but should make it more obvious that they're not class objects and shouldn't be expected to behave like them. In most cases where structs are appropriate, what's needed is a collection of few variables that hold semantically-related but independent values. Open-field structures are a perfect fit, because that's precisely what open-field structures are. Trying to pretend that structures are something else, and working around the limitations thereby, ...
  • supercat
    supercat over 11 years
    @MichaelTaylor3D: ...would be like suggesting that someone who wants to drive a screw should use a hammer along with a device to convert impact into rotation. Hammers may be better for pounding in most of the fasteners one is using, but if one has a screw it would be better to insert it with a screwdriver than try to adapt a hammer to the task.
  • supercat
    supercat over 10 years
    That VB.NET allows extension methods to accept structures by ref would be a good thing, but for the fact that VB will silently copy things which cannot be passed by ref and will pass the copies instead of the originals. If there were a way of telling VB.NET not to do that (the code should instead refuse to compile), such extension methods would be semantically superior to struct instance methods which modify this. I don't know why MS doesn't provide any means by which methods can indicate whether they should be invokable on compiler-generated temporary structures.
  • BrainSlugs83
    BrainSlugs83 over 10 years
    Be careful with this though, as the struct is passed into the extension method BY VALUE (as structs are want to do). Hence, any modifications you make to the struct in the extension method will be lost -- unless you return the struct of course (and then do something with that passed back struct, such as reassign it to itself). There is no way to do an extension method on a struct and have it be passed in by reference (in C#).
  • BrainSlugs83
    BrainSlugs83 over 10 years
    @MichaelTaylor3D why not just make your own rectangle struct (or class) and implement an operator overload that is a widening conversion which converts it to the desired rectangle struct -- this way you can work with it however you want (and just pass it into the methods, etc. which are expecting the other one).
  • BrainSlugs83
    BrainSlugs83 over 10 years
    "... but for the fact that VB will silently copy things which cannot be passed by ref and will pass the copies instead of the originals" -- when does VB do that? -- "byref" is compiled down to the same IL code as "ref" in C# -- my understanding is that anything can be passed by ref in .NET -- the only things that are ever copied are value types (and only when they're not passed by ref).
  • supercat
    supercat over 10 years
    @BrainSlugs83: The approach you describe sometimes works, but often ends up with annoying quirks. What I've sometimes wished for (and thought would be better than "extension methods") would be "extension types". If type X is an extension of Y, a storage location of type X would hold a Y, and for purposes of typecasting would be considered synonymous with Y, but the compiler would attempt to bind members of X before those of Y. One problem with simply using things that are implicitly convertible is that even if X is implicitly convertible to Y and Y to Z...
  • supercat
    supercat over 10 years
    @BrainSlugs83: ...that doesn't allow any sort of conversion from X to Z. On the other hand, if a P were synonymous with Q, and an R with an S, then the existence of a conversion from Q to S would imply conversions from P to S, Q to R, and P` to R. Unfortunately, I know of no .NET languages which support anything like that.
  • BrainSlugs83
    BrainSlugs83 over 10 years
    @Supercat Anything complicated can lead to quirks, you just have to analyze what you need and find the solution with the least amount.
  • cHao
    cHao over 10 years
    @BrainSlugs83: Try passing a read/write property by reference in VB.net. That property is simply the return value of the getter function, not a variable...so passing by reference doesn't work. C# won't allow it. VB will instead fudge pass-by-reference by copying the value, and passing the copy by reference...then when the function returns, will set the property to the new value. Which mostly works, and keeps properties translucent, if you follow LoD and keep structs immutable...but can break in semi-surprising ways when sub-objects and mutable value types get involved.
  • BrainSlugs83
    BrainSlugs83 over 10 years
    I didn't know VB could do that. Sounds like it's not a true "byref" call, but heck -- to me, that actually sounds exactly like how passing a property by reference SHOULD work.. -- Obviously if you do stupid crap with it, your code will break -- but honestly, I really wish C# had the ability to do that. Instead I have to write 4 lines of code every time I want to pass a property by reference -- However -- as I previously suspected, this is completely off-topic.
  • zionpi
    zionpi about 10 years
    It seems like that I cannot extend System.Drawing.Rectangle which is also a struct,and decorated with Serializable and ComVisible and TypeConverter.
  • Zorgarath
    Zorgarath over 5 years
    BrainSlug83 C# 7.2+ now supports refs in struct extension methods.
  • Flying_Banana
    Flying_Banana over 3 years
    This is super useful, as with ref, we can subdivide a Rect - modifying the passed in Rect and returning the new Rect - in a single extension method.