0

chaps/chapettes,我知道有与此相关的问题,但这有些不同 - 我能找到的所有相关问题都只使用一个参数作为示例。无论如何,重点是:

今年,我已经将用 Delphi 编写的源代码转换为 C#。除此之外,我的任务范围一直是优化和总体改进代码库。源代码是由少数人编写的,每个人都没有软件工程原理或技术的知识或经验——所以有些代码是不合格的。

无论如何,也许有人可以为我的争吵提供建议/解决方案:

目前,在 C# 中有一个用于存储 9 个值的类:

class StoreStruct
{
    int A1 { get; set;}
    int B1 { get; set;}
    int C1 { get; set;}

    int A2 { get; set;}
    int B2 { get; set;}
    int C2 { get; set;}

    int A3 { get; set;}
    int B3 { get; set;}
    int C3 { get; set;}
}

现在我遇到的问题是,理想情况下,我想通过 ref 将此类的属性传递给方法。但是,我知道我不能这样做。相反,源代码通过创建临时局部变量来工作,通过 ref 传递这些变量,然后将类属性分配给这些值。这可以如下所示:

private void MethodA()
{
    var temp = new StoreStruct();

    var a1 = 0;
    var b1 = 0;
    var c1 = 0;

    var a2 = 0;
    var b2 = 0;
    var c2 = 0;

    var a3 = 0;
    var b3 = 0;
    var c3 = 0;

    if (expression1)
    {
        MethodB(ref a1, ref b1, ref c1, 1, 1);

        temp.A1 = a1;
        temp.B1 = b1;
        temp.C1 = c1;       
    }

    if (expression2)
    {
        MethodB(ref a2, ref b2, ref c2, 2, 2);

        temp.A2 = a2;
        temp.B2 = b2;
        temp.C2 = c2;   
    }

    if (expression3)
    {
        MethodB(ref a3, ref b3, ref c3, 3, 3);

        temp.A3 = a3;
        temp.B3 = b3;
        temp.C3 = c3;   
    }
}

private void MethodB(ref int a, ref int b, ref int c, int num1, int num2)
{
    a = num1 + num2;
    b = num1 - num2;
    c = num1 * num2;
}

在理想世界中我想做什么:

MethodB(ref temp.A1, ref temp.B1, ref temp.C1, 1, 1);

通过查看其他帖子,我理解了为什么 C# 不支持这一点,坦率地说,我同意它背后的原因。我在其他帖子中看到了一些解决方法和一些建议,但这些仅与一个方法调用的示例有关,并且只有一个参数由 ref 传递。有没有人有一个优雅的解决方案,可以让我更新 MethodB 中的类属性而无需传递临时变量?

4

8 回答 8

1

只需从. getters_settersStoreStruct

于 2013-11-14T16:38:04.933 回答
0

哇,这个问题已经有很多答案了。好吧,这是另一个。您可以尝试创建一个可以作为整数引用的类,如下所示:

class IntRef
{
   private int value;
   public IntRef(int value)
   {
      this.value = value;
   }

   public static implicit operator IntRef(int value)
   {
      return new IntRef(value);
   }

   public static implicit operator int(IntRef value)
   {
      return value.value;
   }
}

然后将您的int声明和参数更改ref intIntRef.

但是请注意,如果您这样做,您的set程序可能无法运行。您可能必须将一些代码移入IntRef类或引发事件,IntRef以便StoreStruct可以对更改的值做出反应。

于 2013-11-14T16:57:04.697 回答
0

好吧,如果是我,我要做的第一件事就是尝试在这里获得一些真实姓名。什么是 A1、B2 等?是收银台吗?一只小狗?太空雪橇?名称应该反映正在发生的事情。接下来,理想情况下,类应该尽可能多地修改自己的数据,所以我倾向于考虑传递对象并在对象上调用尽可能少的方法来做任何需要的修改,而不是传递一组标志,特别是如果后者的名字真的很钝的话。对不起,如果这看起来更像是一种普遍的批评,但它涉及到你提到的关于随着时间的推移改进代码库的任务。(如果它们真的是结构,我总是发现属性是矫枉过正的,除非它们可能有助于调试)。

于 2013-11-14T16:36:21.967 回答
0

您的班级似乎有三组价值观。如果你做一个这样的集合的类,你可以在类中具有三个值:

class ABC {
  int A { get; set; }
  int B { get; set; }
  int C { get; set; }
}

class StoreStruct {

  ABC ABC1 { get; set; }
  ABC ABC2 { get; set; }
  ABC ABC3 { get; set; }

  public StoreStruct {
    ABC1 = new ABC();
    ABC2 = new ABC();
    ABC3 = new ABC();
  }

}

现在您可以将一个ABC值传递给MethodB,因为这是一组可更改的值,您甚至不需要ref参数的关键字:

private void MethodB(ABC abc, int num1, int num2) {
  abc.A = num1 + num2;
  abc.B = num1 - num2;
  abc.C = num1 * num2;
}

称呼:

MethodB(temp.ABC1, 1, 1);

您还可以创建MethodB类的成员ABC,这样您就不会将值传递给方法,而是在值上调用方法:

class ABC {
  int A { get; set; }
  int B { get; set; }
  int C { get; set; }

  public void MethodB(int num1, int num2) {
    A = num1 + num2;
    B = num1 - num2;
    C = num1 * num2;
  }
}

用法:

temp.ABC1.MethodB(1, 1);
于 2013-11-14T16:37:17.030 回答
0

就我个人而言,我会使用您在问题中所做的解决方法。但是,如果您真的想要它,您需要将委托传递给将为您分配值的函数,然后在您的函数中调用它们。

if (expression1)
{
    MethodB((a) => temp1.A1 = a, 
            (b) => temp1.B1 = b, 
            (c) => temp1.C1 = c, 
             1, 1);     
}

private void MethodB(Func<int> setA, 
                     Func<int> setB, 
                     Func<int> setC, 
                     int num1, int num2)
{
    setA(num1 + num2);
    setB(num1 - num2);
    setC(num1 * num2);
}
于 2013-11-14T16:35:01.107 回答
0

属性只不过是 getter 和 setter 函数调用的语法糖,这就是为什么不能通过引用传递它们的原因。一般来说,如果你在 C# 中使用ref参数,你可能做错了。

只需传递StoreStruct对象,然后让函数设置属性。Aclass是一种引用类型,因此基本上所有对象在 C# 中默认情况下都是“通过引用”传递的。

我认为修改你的StoreStruct将有助于解决这个问题,并消除一堆疯狂:

class Thing {
    int A { get; set; }
    int B { get; set; }
    int C { get; set; }
}

class StoreStruct {  //  Not actually a struct!
    public readonly Thing thing1;
    public readonly Thing thing2;
    public readonly Thing thing3;
}

利用:

private void MethodA()
{
    var temp = new StoreStruct();

    if (expression1)
    {
        MethodB(temp.thing1, 1, 1);     
    }

    if (expression2)
    {
        MethodB(temp.thing2, 1, 1);     
    }

    if (expression3)
    {
        MethodB(temp.thing3, 1, 1);     
    }
}

private void MethodB(Thing thing, int num1, int num2)
{
    thing.A = num1 + num2;
    thing.B = num1 - num2;
    thing.C = num1 * num2;
}
于 2013-11-14T16:35:26.050 回答
0

我同意 Jonathan 的评论,即您可能做错了什么,并且可以以不需要通过 ref 传递的方式封装您的状态。

为了做你想做的事,你可以为 getter/setter 使用一个支持变量。

private int _a1;
public int A1
{
  get
  {
    return _a1;
  }
  set
  {
    _a1 = value;
  }
}

public void Foo()
{
  Bar(ref _a1);
}
于 2013-11-14T16:39:20.113 回答
0

看起来你想交换一个类的每个属性。在 OOP 世界中,最好的方法是将完整的类发送给方法,而不仅仅是属性:

public void MethodB(ref StoreStruct store) {
 // store.A1=[...];
}
于 2013-11-14T16:40:05.720 回答