Я следую, чтобы объяснить свою проблему в гораздо большем классе с меньшим простым для понимания точным примером. Я получил довольно большой класс с множеством свойств разных типов, получая и устанавливая соответствующие переменные класса.
public class Foo() {
int property1 { get => _property1 ; set => _property1 = value;}
string property2 { get => _property2 ; set => _property2 = value;}
Vector3 property3 { get => _property3 ; set => _property3 = value;}
bool property4 { get => _property3 ; set => _property4 = value;}
}
Я поставил в пример 4 свойства, но в реальном примере их очень много. Мне нужно применить логику в наборе всех свойств, в зависимости от логического свойства property4, поэтому вместо того, чтобы писать один и тот же код во всех установщиках моих свойств, я попытался сделать общий метод, который будет вызываться во всех из них.
Итак, я сделал перечисление:
public enum properties {
property1,
property2,
property3,
property4
}
Чтобы я мог установить свои свойства с помощью метода, который включает отражение, принимая тип свойства в качестве аргумента:
public void setLogic<T>(properties property, T value) {
//irrelevant code
}
Итак, мои сеттеры становятся:
public class Foo() {
int property1 { get => _property1 ; set { setLogic(properties.property1 , value) };}
string property2 { get => _property2 ; set { setLogic(properties.property2 , value) };}
Vector3 property3 { get => _property3 ; set { setLogic(properties.property3 , value) };}
bool property4 { get => _property4 ; set{ _property4 = value) };}
}
Моя проблема возникает, когда в моем setLogic() установщик свойств вызывается рекурсивно, создавая переполнение стека. Поэтому я решил эту тему с помощью логического значения, управляемого из setLogic(), которое контролирует, откуда вызывается сеттер. Итак, теперь мои свойства выглядят так:
public class Foo() {
int property1 {
get => _property1;
set {
if (!_calledFromSetLogic)
setLogic(properties.property1 , value);
else {
_property1 = value;
_calledFromSetLogic = false;
}
}
}
string property2 {
get => _property2;
set {
if (!_calledFromSetLogic)
setLogic(properties.property2 , value);
else {
_property2 = value;
_calledFromSetLogic = false;
}
}
}
Vector3 property3 {
get => _property3;
set {
if (!_calledFromSetLogic)
setLogic(properties.property3 , value);
else {
_property3 = value;
_calledFromSetLogic = false;
}
}
}
bool property4 { get => property4; set{ _property4 = value) };}
}
Код работает нормально, но элемент управления setter bool, чтобы избежать рекурсии, отбрасывает все возможные чистоты, созданные универсальным методом SetLogic(). С другой стороны, я не могу установить переменные класса в методе setLogic, потому что я обращаюсь к свойствам с отражением, поэтому, чтобы установить новое значение в логике, я не могу избежать рекурсивного набора без логического значения (property.SetValue() из класса отражения устанавливает новое значение, вызывая набор еще раз, поэтому бесконечный цикл).
Если я этого не сделаю, мне придется вставить метод setLogic() вместо общего, скопированного для каждого из свойств в наборе, что также не является очень чистым кодом.
Нет ли для этого чистого решения, где сеттер может быть передан в качестве аргумента, или общего метода, который позволяет избежать бесконечного рекурсивного набора?
Я думал о чем-то вроде
private setLogic<T>(Action<> setterMethod, T value) {
//so that the property involved might be already in the setter?
}
или другой тип setLogic с общими свойствами класса, который позволяет избежать бесконечного цикла, о котором не может думать.
Надеюсь, я дал понять.