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中的类属性,而不必传递临时变量?
答案 0 :(得分:1)
只需从getters
移除setters
和StoreStruct
。
答案 1 :(得分: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);
}
答案 2 :(得分:0)
属性只是getter和setter函数调用的语法糖,这就是你不能通过引用传递它们的原因。通常在C#中,如果你使用ref
参数,那么你可能做错了。
只需传递StoreStruct
对象,然后让函数设置属性。 class
是引用类型,因此在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;
}
答案 3 :(得分:0)
好吧,如果是我,我要做的第一件事就是尝试在这里找到一些真实的名字。什么是A1,B2等?是收银机吗?一只小狗?太空雪橇?名称应反映正在发生的事情。接下来,理想情况下类应该尽可能地修改自己的数据,所以我倾向于考虑传递对象并在对象上调用尽可能少的方法来进行任何需要的修改而不是传递一组标志特别是如果后者的名字真的很钝。很抱歉,如果这看起来更像是一般性的批评,那么它就是你提到的关于随着时间推移改进代码库的任务。 (如果它们真的是结构,我总是发现属性有点过分,除非它们可能有助于调试)。
答案 4 :(得分: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);
答案 5 :(得分:0)
我同意Jonathan的评论,即你可能做错了什么,并且可以以不需要通过ref的方式封装你的州。
为了做你想做的事,你可以为getter / setter使用支持变量。
private int _a1;
public int A1
{
get
{
return _a1;
}
set
{
_a1 = value;
}
}
public void Foo()
{
Bar(ref _a1);
}
答案 6 :(得分:0)
您似乎想要交换类的每个属性。在OOP世界中,最好的方法是将完整的类发送到方法,而不仅仅是属性:
public void MethodB(ref StoreStruct store) {
// store.A1=[...];
}
答案 7 :(得分: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 int
参数更改为IntRef
。
请注意,如果这样做,您的set
程序可能无法运行。您可能必须将部分代码移至IntRef
类或从IntRef
引发事件,以便StoreStruct
可以对更改后的值做出反应。