代码之家  ›  专栏  ›  技术社区  ›  sbi

归纳一个需要处理不同数据成员的算法

c#
  •  4
  • sbi  · 技术社区  · 14 年前

    我有一段这样的代码:

    void someAlgorithm(SomeType someVar)
    {
      someVar.someMember = createSomeValue();
      lock(something)
      {
        SomeType someOtherVar = something.Find(someVar.unrelatedMember);
        if(someOtherVar != null)
          someOtherVar.someMember = someVar.someMember;
      }
    }
    

    (我需要对它进行一些调整,以便发布,所以如果我在发布时弄错了,请耐心等待。)

    现在我需要这段代码 另一成员 属于 someVar (有关联但不同类型)和 另一个创建函数 . 我知道我只需要取下这段代码,复制它,替换一些标识符,然后就可以完成了。但是我这样做感觉很不好。我觉得应该有一种方法来概括这个小算法。

    我知道我总是可以将创建函数作为委托传递,但是我不知道如何概括成员访问,然后会出现这些成员(和创建函数)具有不同类型的问题。

    在C++中,我将使用与模板结合的成员指针来执行此操作。成员指针并不是一块可以使用的蛋糕,但是一旦我找到了它们奇怪的语法,我就可以在几分钟内完成。如何在C中做到这一点?

    编辑: 由于这看起来不够清楚,下面是同一算法的另一个实例:

    void someOtherAlgorithm(SomeOtherType someVar) // 1 change here
    {
      someVar.someOtherMember = createSomeOtherValue(); // 2 changes here
      lock(something)
      {
        SomeOtherType someOtherVar = something.Find(someVar.unrelatedMember);
        if(someOtherVar != null)
          someOtherVar.someOtherMember = someVar.someOtherMember; // 2 changes here
      }
    }
    

    我希望这能澄清这一点。

    3 回复  |  直到 14 年前
        1
  •  3
  •   Dan Tao    14 年前

    你让我有点困惑。你的 someAlgorithm 接受类型为的参数 SomeType 打电话 someOtherVar 并声明一个同名的局部变量(因此无法按原样编译)。从你的两个定义来看 someVar 某物 是同一类型的( 基类型 ,但是您的局部变量只能用 var 因此,还不完全清楚它们是否存在。

    在你对slaks的评论中,你暗示 萨默瓦尔 某物 是不同类型的(即使在你引用的问题中,你谈论的是 萨默瓦尔 当Slaks询问你的两个变量时 萨默瓦尔 某物 )所以我假设它们是不同的类型 某物 只是局部变量,不是参数。

    基于这些假设:

    void someAlgorithm<TMember>(
        SomeType someVar,
        Func<TMember> create,                   // replaces "createSomeValue"
        Func<SomeType, TMember> getter,         // replaces get for "someMember"
        Action<SomeType, TMember> setter,       // replaces set for "someMember"
        Action<SomeOtherType, TMember> setter2) // replaces set for "someMember"
                                                // on "someOtherVar" (not necessary
                                                // if "someOtherVar" is actually
                                                // the same type as "someVar")
    {
      setter(somevar, create());
    
      lock(something)
      {
        SomeOtherType someOtherVar = something.Find(someVar.unrelatedMember);
    
        if(someOtherVar != null)
          setter2(someOtherVar, getter(someVar));
      }
    }
    

    对于您的第一个算法,这称为:

    someAlgorithm(
        someVar,
        createSomeValue,
        x => x.someMember,
        (x, y) => { x.someMember = y; },
        (x, y) => { x.someMemberOfOtherType = y; }
    );
    

    对于您的第二个:

    someAlgorithm(
        someVar,
        createSomeOtherValue,
        x => x.someOtherMember,
        (x, y) => { x.someOtherMember = y; },
        (x, y) => { x.someOtherMemberOfOtherType = y; }
    );
    
        2
  •  3
  •   Tomas Petricek    14 年前

    我认为最好的选择是使用 Func 委托简单的选择器函数并将其作为参数传递给算法。可以将该方法设为泛型,以便选择器可以返回任何类型的成员:

    void someAlgorithm<T>(SomeType someVar, SomeType someOtherVar, 
                          Func<SomeType, T> selector) { 
      someVar.someMember = createSomeValue(); 
      lock(something) { 
        var someOtherVar = something.Find(selector(someVar));  // Use 'selector'
        if(someOtherVar != null) 
          someOtherVar.someMember = someVar.someMember; 
      } 
    } 
    

    然后你可以写一些像:

    someAlgorithm(some1, some2, a => a.SomeOtherMember);
    

    如果没有关于实际代码的更多详细信息,则很难精确地编写答案(例如,您可能需要对泛型类型参数进行一些约束,例如。 IComparable 如果要比较这些值),但这通常是解决问题的最佳方法。

    如果在设置/获取值的代码中需要另一个参数化, someMember 然后您只需添加其他函数。例如 Action<SomeType, T> (设置值)和另一个成员的一个“selector”函数。在电话里,这是 (s, val) => s.SomeMember = val . 如果 一员 有一个不同的类型,那么您可能需要再添加一个类型参数。

        3
  •  1
  •   SLaks    14 年前

    可以传递创建和设置值的lambda表达式。

    例如:

    void someAlgorithm<TObject, TProperty>(TObject someVar, Func<TProperty> creator, Action<TObject, TProperty> setter, Action<SomeType, TProperty> relatedSetter)
    {
      var value = creator();
      setter(someVar, value);
      lock(something)
      {
        var someOtherVar = something.Find(someVar.SomeOtherMember);
        if(someOtherVar != null)
          relatedSetter(someOtherVar, value);
      }
    }
    
    
    someAlgotihm(something, createSomeValue, (x, v) => x.someProperty = v, (x, v) => x.someProperty = v);