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);
}
}
我希望能够创建一个对任何成员变量执行通用操作的函数。
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);
}
}