【问题标题】:Avoid creating duplicate method which only needs a different operator避免创建只需要不同运算符的重复方法
【发布时间】:2021-06-02 13:20:44
【问题描述】:

我有一些方法可以返回给定位置最近的Foo后面

public Foo ClosestFooBehindPosition(float pos)
{
    Foo closestFoo = null;

    foreach (Foo foo in FooManager.Foos)
    {
        if (foo.Pos < pos)
        {
            if (closestFoo = null) closestFoo = foo;
            else
            {
                bool thisFooIsCloser = closestFoo.pos > foo.Pos;
                if (thisFooIsCloser) closestFoo = foo;
            }
        }
    }
    return closestFoo;
}

我还需要一个返回给定位置最近的FooAhead

有没有一种不需要复制大部分方法的方法,因为唯一的区别是交换&lt;&gt;

【问题讨论】:

    标签: c# operators


    【解决方案1】:

    您可以传递一个评估它的 lambda/函数参数。

    例如:

    // use the Func<,,> for this.
    public Foo ClosestFooPosition(Func<float, float, bool> evaluator, float pos)
    {
        Foo closestFoo = null;
    
        foreach (Foo foo in FooManager.Foos)
        {
            // just call it here to evualuate it.
            if (evaluator(foo.Pos, pos))
            {
                if (closestFoo = null) closestFoo = foo;
                else
                {
                    // don't forget here also. 
                    bool thisFooIsCloser = !evaluator(foo.Pos, closestFoo.pos);                                            
                    if (thisFooIsCloser) closestFoo = foo;
                }
            }
        }
        return closestFoo;
    }
    

    这样称呼:

    // define a function for it...
    private bool GreaterThan(float first, float second)
    {
        return first > second;
    }
    
    // pass the function without the parentesis
    var fooBehind = ClosestFooPosition(GreaterThan, pos);
    

    甚至更短:

    // inline the function as lambda
    var fooBehind = ClosestFooPosition((first, second) => first > second, pos);
    
    var fooAhead = ClosestFooPosition((first, second) => first < second, pos);
    

    【讨论】:

      【解决方案2】:

      如果Foo 实现IComparable,您可以使用System.LinqWhereMax/Min 方法。

      class Foo: IComparable<Foo>
      {
          int IComparable<Foo>.CompareTo(Foo other)
          {
              if (other.Pos > this.Pos) return -1;
              if (other.Pos == this.Pos) return 0;
              if (other.Pos < this.Pos) return 1;
          }
      }
      
      // Find the largest value of `Pos` that's less than `pos`.
      public Foo ClosestFooBehindPosition(float pos) =>
          FooManager?.Foos?.Where(foo => foo.Pos < pos).Max();
      
      // Find the smallest value of `Pos` that's larger than `pos`.
      public Foo ClosestFooAfterPosition(float pos) =>
          FooManager?.Foos?.Where(foo => foo.Pos > pos).Min();
      

      因为使用了null-conditional (?.) operator,如果FooManagerFooManager.Foos,或者Max/Min的结果是null,那么你仍然会从你的方法中得到null (s)。


      如果您无法更改 Foo 或者您可能想保留 IComparable&lt;Foo&gt; 以供其他用途,您可以 OrderBy Foo.Pos 属性并获取 First/Last 以达到相同的结果.

      public Foo ClosestFooBehindPosition(float pos) =>
          FooManager?.Foos?.Where(foo => foo.Pos < pos)
                           .OrderBy(foo => foo.Pos)
                           ?.Last();
      
      public Foo ClosestFooAfterPosition(float pos) =>
          FooManager?.Foos?.Where(foo => foo.Pos > pos)
                           .OrderBy(foo => foo.Pos)
                           ?.First();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-27
        • 2015-08-29
        • 1970-01-01
        相关资源
        最近更新 更多