首页 > 解决方案 > C# 是否有指向 C++ 中的成员的指针?

问题描述

在 C++ 中,您可以编写以下代码:

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

Animal a;

a.*pAge = 50;

C#中是否有类似的功能?

编辑:为了澄清,我不是在问指针。我问的是“指向成员的指针”,这是 C++ 中与.*and->*运算符一起使用的一个特性。


编辑 2:这是成员指向指针的用例示例。

假设我们有以下类:

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

假设我们要编写可以找到平均年龄/身高/体重/等的方法。数组中的所有动物。然后我们可以这样做:

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
}

我们最终会在这里复制和粘贴大量代码,如果我们查找平均值的算法发生变化,我们将遇到维护噩梦。因此,我们想要对任何成员的这个过程进行抽象。考虑这样的事情:

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

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

    return average/animals.length;
}

然后我们可以调用

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

或类似的东西。然而,使用委托比它必须的要慢;我们使用整个函数只是为了返回结构中某个位置的值Animal。在 C++ 中,指向指针的成员允许您对结构进行指针数学运算(不是正确的术语,但我想不出更好的术语)。正如你可以说的

int p_fourthAnimal = 3;

(animals + p_fourthAnimal)*

要在存储在变量中的指针之前获取这么多字节的值animals,在 C++ 中,您可以说

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

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

在存储在变量中的指针之前获取这么多字节的值animal;从概念上讲,编译器将animal.*p_age变成(animal + [the appropriate offset])*. 因此,我们可以将我们averageAttribute的声明为:

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

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

    return average/animals.length;
}

然后我们可以调用

averageAttribute(animals, &Animal::age);

总之,指向成员的指针允许您将诸如我们的方法抽象averageAttribute到结构的所有成员,而无需复制和粘贴代码。虽然委托可以实现相同的功能,但如果您知道实际上不需要函数分配给您的自由,那么获取结构成员的效率相当低,甚至可能存在边缘用例,其中委托是不够的,但我无法给出此类用例的任何示例。C# 有类似的功能吗?

标签: c#pointerspointer-to-member

解决方案


正如其他人在这里评论的那样,委托是在 C# 中实现此目的的方法。

虽然委托可以实现相同的功能,但如果您知道您实际上并不需要函数分配给您的自由,那么获取结构成员的效率相当低

这取决于编译器和运行时如何实现该委托。他们很可能会看到这是一个微不足道的函数,并优化了调用,就像他们对微不足道的 getter 和 setter 所做的那样。例如,在 F# 中,您可以实现:

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

推荐阅读