2013-11-14 2 views
0

chaps/chapettes, я понимаю, что есть вопросы, связанные с этим, но это несколько другое - все связанные вопросы, которые я мог найти, использовали только один параметр в качестве примера. В любом случае, до:Недвижимость по ref C# (много параметров)

В этом году я преобразовал исходный код, написанный на 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;} 
} 

что теперь у меня есть проблема с том, что , в идеале, я хотел бы передать свойства этого класса в методы по ссылке. Однако я знаю, что не могу этого сделать. Вместо этого исходный код работает, создавая временные переменные temp, передает их по 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

Можете ли вы передать «StoreStruct» в методы? – Chris

+7

Свойства - это не что иное, как синтаксический сахар для вызовов функции getter и setter, поэтому вы не можете передавать их по ссылке. В общем случае в C#, если вы используете ref params, вы делаете это неправильно. Просто передайте класс StoreStruct и пусть функция задает свойства. Класс является ссылочным типом, поэтому по существу все объекты передаются «по ссылке» по умолчанию в C#. –

+0

Будет ли смысл создавать массивы 'A',' B' и 'C'? Это может облегчить работу.Вы можете просто заменить их или создать свойства 'IList ' с классом, который просто имитирует его (например, так, что 'A [1] = 3524' устанавливает' A1'), чтобы хотя бы централизовать эту запутанную логику, а не везде , но это может быть более запутанным. –

ответ

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); 
} 
0

Свойства ничего, кроме синтаксического сахара для геттер и сеттер вызовов функций, поэтому вы не можете передавать их по ссылке. Обычно в C#, если вы используете параметры ref, вы, вероятно, ошибаетесь.

Просто передайте объект StoreStruct, и пусть функция задает свойства. A 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; 
} 
0

Ну, если бы это было мне первое, что я хотел бы сделать пытается получить здесь настоящие имена. Что такое A1, B2 и т. Д.? Это кассовый аппарат? Щенок? Космические сани? Имена должны отражать то, что происходит. Затем, в идеале, классы должны как можно больше модифицировать свои данные, поэтому я хотел бы думать о передаче объекта и называть как можно меньше методов для того, чтобы делать какие-либо изменения, а не передавать вокруг множества флагов , особенно если последние имеют действительно тупые имена.Извините, если это похоже на общую критику, но это относится к тому, что вы упомянули о том, что вам нужно улучшить кодовую базу с течением времени. (Если они действительно структурированы, я всегда считал свойства излишними, за исключением тех случаев, когда они могли бы помочь отладки).

+0

Вышеприведенный пример является абстрактным примером с родовыми именами. Я не могу опубликовать фактический код по договорным причинам. – dw1991

+0

OK, извините, мой плохой. –

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); 
1

Просто удалите getters и setters от StoreStruct.

+0

Я считаю это плохим решением. Если бы ОП мог просто сделать их полями, он/она уже это сделал бы. Кроме того, вы меняете другое поведение, например. поля не являются полиморфными. – Zong

0

Я согласен с комментарием Джонатана, что вы, вероятно, делаете что-то неправильно и можете инкапсулировать свое состояние таким образом, чтобы не требовать прохождения по ref.

Для того, чтобы делать то, что вы хотите, вы можете использовать опорную переменную для геттеров/сеттеров.

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

public void Foo() 
{ 
    Bar(ref _a1); 
} 
0

Похоже, что вы хотите обменять каждый свойство класса. В ООП-мире лучший способ сделать это, чтобы отправить полный класс к методу, а не только свойства:

public void MethodB(ref StoreStruct store) { 
// store.A1=[...]; 
} 
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 может отреагировать на измененное значение.

 Смежные вопросы

  • Нет связанных вопросов^_^