将属性作为参数传递

缺口

我正在创建一个价值函数计算器,对于未使用它的人,需要选择一些属性,然后根据这些属性与某些理想值的接近程度来计算一个值(价值函数)。然后,这使用户能够找到最符合其要求的项目。

这是我要使用的代码:

public class MeritFunctionLine
{
    public Func<CalculationOutput, double> property { get; set; }
    public double value { get; set; }
    public ComparisonTypes ComparisonType { get; set; }
}

public class MeritFunction
{
    public List<MeritFunctionLine> Lines { get; set; }
    public double Calculate(CalculationOutput values)
    {
        double m = 0;
        foreach (var item in Lines)
        {
            m += Math.Abs(values.property - item.value);
        }
        return m;
    }
}

public class CalculationOutput
{
    public double property1 { get; set; }
    public double property2 { get; set; }
    public double property3 { get; set; }
    public double property4 { get; set; }
}

显然,这不会编译,因为不包含称为property的成员,但这是我要执行的操作的说明:

  1. 创建一个新的MeritFunction
  2. 将任意数量的MeritFunctionLines添加到MeritFunction.Lines
  3. MeritFunctionLine.property应该指定应该在MeritFunction.Calculate中比较CalculationOutput的哪个属性。

MeritFunction mf = new MeritFunction();
mf.Lines.Add(new MeritFunctionLine() { property = x => x.Property1, value = 90, comparisonType = ComparisonTypes.GreaterThan });
mf.Lines.Add(new MeritFunctionLine() { property = x => x.Property3, value = 50, comparisonType = ComparisonTypes.Equals });

CalculationOutput c1 = new CalculationOutput() { property1 = 1, property2 = 20, property3 = 150, property4 = 500 };
CalculationOutput c2 = new CalculationOutput() { property1 = 15, property2 = 32, property3 = 15, property4 = 45 };

double value1 = mf.Calculate(c1);
double value2 = mf.Calculate(c2);

我不是在问如何将属性作为参数传递给函数,这是C#禁止的。

梅多42

您几乎已经有了正确的解决方案-唯一缺少的部分是如何使用MeritFunctionLine.property属性从中获取所需的值CalculationOutput

foreach循环中,只需将计算行替换为

m += Math.Abs(item.property(values) - item.value);

编辑:

增加通用性

要解决黑曜石凤凰社的评论,您可以通过同时使用MeritFunctionMeritFunctionLine通用将其用于不同的类,因此:

public class MeritFunctionLine<TCalcOutput>
{
    public Func<TCalcOutput, double> property { get; set; }
    public double value { get; set; }
    public ComparisonTypes ComparisonType { get; set; }
}

public class MeritFunction<TCalcOutput>
{
    public List<MeritFunctionLine<TCalcOutput>> Lines { get; set; }
    public double Calculate(TCalcOutput values)
    {
        double m = 0;
        foreach (var item in Lines)
        {
            m += Math.Abs(item.property(values) - item.value);
        }
        return m;
    }
}

重写的用法示例将是

MeritFunction<CalculationOutput> mf = new MeritFunction<CalculationOutput>();
mf.Lines.Add(new MeritFunctionLine<CalculationOutput>() { property = x => x.Property1, value = 90, comparisonType = ComparisonTypes.GreaterThan });
mf.Lines.Add(new MeritFunctionLine<CalculationOutput>() { property = x => x.Property3, value = 50, comparisonType = ComparisonTypes.Equals });

CalculationOutput c1 = new CalculationOutput() { property1 = 1, property2 = 20, property3 = 150, property4 = 500 };
CalculationOutput c2 = new CalculationOutput() { property1 = 15, property2 = 32, property3 = 15, property4 = 45 };

double value1 = mf.Calculate(c1);
double value2 = mf.Calculate(c2);

一些额外的便利

如果MeritFunctionLine要添加许多,则上面的语法可能会有些乏味。因此,作为奖励,让我们进行更改,MeritFunction以便可以使用列表初始化语法对其进行初始化。为此,我们需要IEnumerable使其具有Add功能:

public class MeritFunction<TCalcOutput> : IEnumerable<MeritFunctionLine<TCalcOutput>>
{
    public List<MeritFunctionLine<TCalcOutput>> Lines { get; set; }

    public MeritFunction()
    {
        Lines = new List<MeritFunctionLine<TCalcOutput>>();
    }

    public void Add(Func<TCalcOutput, double> property, ComparisonTypes ComparisonType, double value)
    {
        Lines.Add(new MeritFunctionLine<CalculationOutput>
        {
            property = property,
            value = value,
            comparisonType = ComparisonType
        });
    }

    public double Calculate(TCalcOutput values)
    {
        double m = 0;
        foreach (var item in Lines)
        {
            m += Math.Abs(item.property(values) - item.value);
        }
        return m;
    }

    public IEnumerator<MeritFunctionLine<TCalcOutput>> GetEnumerator()
    {
        return List.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

请注意,该Add方法以不同的顺序接收参数-当您查看用法时,您会理解为什么。相当多的额外代码,但是现在创建我们的代码会MeritFunction更好一些:

MeritFunction<CalculationOutput> mf = new MeritFunction<CalculationOutput>
{
    { x => x.Property1, ComparisonTypes.GreaterThan, 90 },
    { x => x.Property3, ComparisonTypes.Equals,      50 }
};

注意,所有代码未经测试。使用风险自负:)

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章