C#有成员指针等在C ++?

时间:2019-02-01 10:35:56

标签: c# pointers pointer-to-member

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

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

Animal a;

a.*pAge = 50;

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

修改:要澄清,我的的询问指针。我问的是“成员指针”,这是C ++中与.*->*运算符一起使用的功能。


修改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)*

在C ++中,要使该值比存储在变量animals中的指针领先那么多字节,您可以说

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#是否具有类似的功能?

3 个答案:

答案 0 :(得分:2)

正如其他人在这里评论的那样,委托是在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

答案 1 :(得分:0)

不,c#没有像c ++一样指向(引用)对象成员的功能。

但是为什么呢? 指针被认为是不安全的。而且即使在不安全的区域中,您也不能指向引用或包含引用的结构,因为即使指针指向对象引用也可以被垃圾回收。垃圾收集器不会跟踪任何指针类型是否指向对象。

  • 您提到了很多重复代码用于非指针方式实现,这是不正确的。

  • 速度取决于JIT的编译速度,但是您没有测试吗?

  • 如果确实遇到性能问题,则需要考虑数据结构,而不必考虑访问成员的某种方式。

如果认为您的Q下的注释数量表明您没有真正遇到c#的普遍接受的缺点

var Animals = new Animal[100];
 //fill array

var AvgAnimal = new Animal() {
    age = (int)Animals.Average(a => a.age ),
    height = (int)Animals.Average(a => a.height),
    weight = (int)Animals.Average(a => a.weight)
};

c#的unsafe区域通过指针为some ways访问成员提供服务,但仅适用于单个结构之类的值类型,而不适用于结构数组。

struct CoOrds
{
public int x;
public int y;
}

class AccessMembers
{
static void Main() 
{
    CoOrds home;

    unsafe 
    {
        CoOrds* p = &home;
        p->x = 25;
        p->y = 12;

        System.Console.WriteLine("The coordinates are: x={0}, y={1}", p->x, p->y );
    }
  }
}

答案 2 :(得分:0)

使用委托可以得到相同的行为,但这与委托是C ++中函数的指针不同。您试图实现的目标在C#中是可能的,但在C ++中却无法实现。

我考虑使用Func的解决方案:

public class Animal
{
    public int Age { get; set; }
    public int Height { get; set; }
    public double Weight { get; set; }
    public string Name { get; set; }

    public static double AverageAttributeDelegates(List<Animal> animals, Func<Animal, int> getter)
    {
        double average = 0;

        foreach(Animal animal in animals)
        {
            average += getter(animal);
        }

        return average/animals.Count;
    }
}
List<Animal> animals = new List<Animal> { new Animal { Age = 1, Height = 2, Weight = 2.5, Name = "a" }, new Animal { Age = 3, Height = 1, Weight = 3.5, Name = "b" } };
Animal.AverageAttributeDelegates(animals, x => x.Age); //2
Animal.AverageAttributeDelegates(animals, x => x.Height); //1.5

它正在运行,但是由于func被声明为int,因此您必须绑定到属性Func<Animal, int>的类型。您可以设置为object并处理演员表:

public static double AverageAttributeDelegates2(List<Animal> animals, Func<Animal, object> getter)
{
    double average = 0;

    foreach(Animal animal in animals)
    {
        int value = 0;
        object rawValue = getter(animal);
        try
        {
            //Handle the cast of the value
            value = Convert.ToInt32(rawValue);
            average += value;
        }
        catch(Exception)
        {}
    }

    return average/animals.Count;
}

示例:

Animal.AverageAttributeDelegates2(animals, x => x.Height).Dump(); //1.5
Animal.AverageAttributeDelegates2(animals, x => x.Weight).Dump(); //3
Animal.AverageAttributeDelegates2(animals, x => x.Name).Dump(); //0