Search code examples
c#pointerspointer-to-member

Does C# have pointers to members like in C++?


In C++, you could write the following code:

int Animal::*pAge= &Animal::age;

Animal a;

a.*pAge = 50;

Is there similar functionality in C#?

Edit: To clarify, I am not asking about pointers. I am asking about "pointers to members", a feature found in C++ that is used with the .* and ->* operators.


Edit 2: Here is an example of a use case for members to pointers.

Let's say we have the following class:

class Animal
{
    int age;
    int height;
    int weight;
    …
}

And let's say that we want to write methods that will find the average age/height/weight/etc. of all Animals in an array. We could then do this:

int averageAge(Animal[] animals)
{
    double average = 0;

    for (…)
        average += animals[i].age;

    return average/animals.length;
}

int averageHeight(Animal[] animals)
{
    //code here again
}

int averageWeight(Animal[] animals)
{
    //code here again
}

We would end up copying and pasting a lot of code here, and if our algorithm for finding the average changed, we would encounter a maintenance nightmare. Thus, we want an abstraction of this process for any member. Consider something like this:

int averageAttribute(Animal[] animals, Func<Animal, int> getter)
{
    double average = 0;

    for (…)
        average += getter(animals[i]);

    return average/animals.length;
}

which we could then call with

averageAttribute(animals, (animal) => animal.age);

or something similar. However, using delegates is slower than it has to be; we are using an entire function just to return the value at a certain location in the Animal struct. In C++, members to pointers allow you to do pointer math (not the right term but I can't think of a better term) on structs. Just as you can say

int p_fourthAnimal = 3;

(animals + p_fourthAnimal)*

to get the value so many bytes ahead of the pointer stored in the variable animals, in C++, you could say

int Animal::* p_age = &Animal::age;

animal.*p_age //(animal + [the appropriate offset])*

to get the value so many bytes ahead of the pointer stored in the variable animal; conceptually, the compiler will turn animal.*p_age into (animal + [the appropriate offset])*. Thus, we could declare our averageAttribute as this instead:

int averageAttribute(Animal[] animals, Animal::* member)
{
    double average = 0;

    for (…)
        average += animals[i].*member; //(animals[i] + [offset])*

    return average/animals.length;
}

which we could then call with

averageAttribute(animals, &Animal::age);

In summary, pointers to members allow you to abstract a method such as our averageAttribute to all members of a struct without having to copy and paste code. While a delegate can achieve the same functionality, it is a rather inefficient way to get a member of a struct if you know you do not actually need the freedom allotted to you by a function, and there could even be edge use cases in which a delegate does not suffice, but I could not give any examples of such use cases. Does C# have similar functionality?


Solution

  • As other people have commented here, delegates are the way to achieve this in C#.

    While a delegate can achieve the same functionality, it is a rather inefficient way to get a member of a struct if you know you do not actually need the freedom allotted to you by a function

    It depends how the compiler and runtime implement that delegate. They could very well see that this is a trivial function and optimize the call away, like they do for trivial getters and setters. In F# for instance you can achieve this:

    type Animal = { Age : int }
    
    let getAge (animal:Animal) =
        animal.Age
    
    let inline average (prop:Animal->int) (animals:Animal[]) =
        let mutable avg = 0.
        for animal in animals do
            avg <- avg + float(prop(animal)) // no function call in the assembly here when calling averageAge
        avg / (float(animals.Length))
    
    let averageAge = average getAge