Является ли плохой практикой передавать "this" в качестве аргумента?
В настоящее время я соблазнился написать следующее:
public class Class1()
{
public Class1()
{
MyProperty = new Class2(this);
}
public Class2 MyProperty { get; private set; }
}
public class Class2()
{
public Class2(Class1 class1)
{
ParentClass1 = class1;
}
public Class1 ParentClass1 { get; set; }
}
Передача "this" в качестве аргумента признака проблемы проектирования? Что было бы лучше?
Ответы
Ответ 1
Нет, нет фундаментальной проблемы проектирования с прохождением this
. Очевидно, что это может быть неправильно использовано (создание связи, слишком жесткое из-за того, что связанный класс зависит от значений, хранящихся в вашем экземпляре, когда, например, вызываются его собственные значения), но нет общей проблемы с ним.
Ответ 2
нет, это не проблема. Именно поэтому существует 'this' ключевое слово, чтобы вы могли обойти
Ответ 3
Трудно сказать, что вы опубликовали. Вопрос, который вы должны задать себе: почему класс 2 должен знать о классе1? Какие типы операций выполняет класс 2 для класса 1 в течение его жизни, и есть ли лучший способ реализовать это отношение?
Имеются веские причины для этого, но это зависит от фактических классов.
Ответ 4
В общем, я бы предпочел передать интерфейс вместе с "дочерним" классом, поскольку это уменьшает сцепление. Если Class2 действительно нуждается в доступе ко всем службам Class1, и Class2 является общедоступным таким образом (не полностью инкапсулированным и построенным Class1), тогда я бы предпочел потребовать, чтобы конкретный экземпляр Class1 в конструкторе был признаком возможной проблемы с дизайном.
Ответ 5
Просто для облегчения вашего ума:
Передача this
в качестве параметра выполняется даже классами внутри BCL. Например, тип List<T>.Enumerator
содержит ссылку на его родительский объект List<T>
, чтобы знать, был ли список изменен между перечислениями (и, следовательно, когда нужно было выбросить InvalidOperationException
).
Это довольно стандартно, когда у вас есть два (или более) типа, которые фактически принадлежат друг другу в тесно связанной, логически связанной группе (например, вышеупомянутой коллекции и перечислителя). Я видел много случаев, когда разработчики наклонились назад, чтобы избежать такого рода разумной связи без каких-либо практических соображений.
Ответ 6
Чтобы привести пример, проверьте шаблон посетителя:
interface IVisitor {
Visit(SomeClass c);
Visit(AnotherClass c);
}
interface IAcceptVisitor {
void Accept(IVisitor v);
}
public SomeClass : IAcceptVisitor {
void Accept(IVisitor v) {
v.Visit(this);
}
}
Ответ 7
Я не знаю модель памяти в С# подробно (вообще). Но передача этого из конструктора в другой объект по своей сути является небезопасной на многих языках (включая Java).
Если вы находитесь в конструкторе, объект еще не сконструирован. Если другой объект решает использовать переданный этот аргумент в данный момент, он ссылается на объект в состоянии undefined.
В вашем примере такого использования undefined не происходит, но как бы вы гарантировали, что этого не будет в будущем? Что делать, если кто-то подклассы/изменяет Class2 таким образом, что он использует что-то из ParentClass1 в своем собственном конструкторе?
Ответ 8
Нет проблем, если есть четкая потребность в отношениях в вашем дизайне. Этот шаблон часто используется в различных приложениях для указания "родительский" или "владелец".
Я особенно использовал его при пересечении деревьев в реализациях компилятора или в инструментах GUI.