C# 模板访问对象成员

C# templating access to object members

我希望能够创建一个对任何成员变量执行通用操作的函数。

class line
{
    double angle;
    double length;
    public void add(reference member, double scalar)
    {
        this.member *= scalar;
    }
}

这在 C# 中可行吗?如果我有很多成员变量,我不想创建一个巨大的 switch case。我也不想为每个成员变量创建一个 lambda 函数,因为操作是相同的。

不需要泛型。不过,您必须为不同的标量类型重载。在 C# 中无法使用泛型对标量进行算术运算。为此,您需要一个类型约束 where T : scalar ,不幸的是,它不存在(并且可能不存在)。

class line
{
    double angle;
    double length;

    public void add(ref double member, double scalar)
    {
        member *= scalar;
    }

    public void test()
    {
        add(ref angle, 12);
    }

}

您也可以将其定义为任何 class:

的扩展方法
public static class Extensions
{
    public static double add(this object o, ref double d1, double d2)
        => d1 *= d2;
}

但是你必须明确地给它加上前缀 this.:

private double _x = 1.0;
public void Test()
{
    //  "The name 'add' does not exist in the current context"
    add(ref _x, 1.2);

    //  This compiles
    this.add(ref _x, 1.2);
}

使用反射如下,现在可以这样操作:line.Add(l => l.Length, 10) or line.Add("Length", 10) or line.Add(nameof(line.Length), 10)(env >.net 4.5)

您还可以像这样迭代特殊成员:(new List<string> { "Length", "Height" }).ForEach(p => line.Add(p, 10))

class Line
{
    public int Length { get; set; }

    public double Height { get; set; }

    public void Add<O>(Expression<Func<Line, O>> accessor, dynamic scale) where O : struct
    {
        Add((accessor.Body as MemberExpression).Member.Name, scale);//simply get name from expression
    }

    public void Add(string name, dynamic scale)
    {
        var prop = typeof(Line).GetProperty(name);//can also get all members
        dynamic a = prop.GetValue(this);
        prop.SetValue(this, a * scale);
    }
}

根据@askpark 的回答,我想出了一些更简单的方法

class line
{
    double angle;
    double length;

    public void delegate adder(line l, double d);
    static adder angleAdder = (l,d) => {l.angle += d};
    static adder lengthAdder = (l,d) => {l.length += d};

    public void add(adder addFunc, double scalar)
    {
        addFunc(this, scalar);
    }
}