C# delegate to struct method
Asked Answered
R

3

6

I am trying to create a delegate to a struct method for a particular instance. However, it turns out that a new instance of the struct is created and when I call the delegate it performs the method over the newly created instance rather than the original.


static void Main(string[] args)
{
Point A = new Point() { x = 0 };
Action move = A.MoveRight;
move();
//A.x is still zero!
}

struct Point
{
    public int x, y;

    public void MoveRight()
    {
        x++;
    }
}

Actually, what happens in this example is that a new instance of struct Point is created on the delegate creaton and the method when called through the delagate is performed on it.

If I use class instead of the struct the problem is solved, but I want to use a struct. I also know there is a solution with creating an open delegate and passing the struct as the first parameter to a delegate, but this solution seems rather too heavy. Is there any simple solution to this problem?

Rolanderolando answered 23/2, 2011 at 2:44 Comment(1)
If this is really performance sensitive code and you need structs, then avoid using delegates altogether. If you haven't profiled this code and don't even know whether this code will be a bottleneck for you, then just either use a class or pass the struct as a parameter to the delegate.Sparrow
K
9

No, there's no way around this. Do you have a specific reason to use struct? Unless you have a particular need for it, you really should be using class.

Incidentally, you have created a mutable struct (a struct whose values can change), which is, without exaggeration, anathema. You need to be using a class.

Klipspringer answered 23/2, 2011 at 2:47 Comment(3)
Well, his struct is a 2D point, and contains only 8 bytes, so he may have a good reason.Sparrow
also calling mutable structs anathema might be a bit of an exaggeration. When developing for the Xbox 360 in XNA/C#, sometimes mutable structs are your only option for fast code (since the Xbox uses the compact CLR).Sparrow
@TheBigO: I'll grant that there exist circumstances for which mutable structs are appropriate, but I am willing to say that if someone is asking questions like this about structs (indicating that the intricacies of value-type semantics, which are crucial to such development, are not clear to the OP) then it's something they should categorically avoid.Klipspringer
C
6

Mutable structs are evil and shouldn't be used!*

You could change your struct to be immutable and your MovePoint method to return a new value of the struct:

struct Point {
    private readonly int x, y;
    public Point(x, y) { 
        this.x = x; this.y = y;
    }

    public struct MoveRight() {
        x++;
    }
}

Then you'd use Func<Point, Point> to represent operation that changes the point:

Func<Point, Point> move = a => a.MoveRight;

Point A = new Point() { x = 0 };
Point newA = move(A);
// newA.x is 1, but A.x is still 0, because struct is immutable
Point anotherA = move(newA);
// move the point again...

*) Sure, there are situations where they may be useful, but if your situation was one of them, you wouldn't be asking this question.

Chromoplast answered 23/2, 2011 at 2:50 Comment(2)
What is the => operator doing in this context?Sparrow
@TheBigO: it is a declaration of lambda function - it creates a delegate that takes Point as argument, calls its MoveRight method and returns the result. (Search for C# 3.0 lambda syntax)Chromoplast
W
4

Anathema or not maybe in office use of C#. In 3D engines we do any kind of devil work. So for example in Unity3D engine Vector3 is struct by you have function Set(x,y,z) and you can even change x,y,z as they are public fields. Everything for speed(e.g if you have less calculation for this, you will have for something else.

  static void Main(string[] args)
    {
    Point A = new Point() { x = 0 };
    MyPointDelegate<Point> move=(ref Point p)=> p.MoveRight();
    move(ref A);
    Console.Write(A.x);
    //A.x is one!
    }



public delegate void MyPointDelegate<Point>(ref Point t);

struct Point
{
    public int x, y;

    public void MoveRight()
    {
        x++;
    }
}
Woodley answered 28/5, 2019 at 11:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.