Короткая версия
Для тех, у кого нет времени читать мои рассуждения по этому вопросу ниже:
Есть ли способ применить политику "только новые объекты" или "только существующие объекты" для параметров метода ?
Длинная версия
Существует множество методов, которые принимают объекты в качестве параметров, и не имеет значения, имеет ли метод объект «все для себя» или нет. Например:
var people = new List<Person>();
Person bob = new Person("Bob");
people.Add(bob);
people.Add(new Person("Larry"));
Здесь метод List<Person>.Add
взял «существующий» Person
(Боб), а также «новый» Person
(Ларри), и список содержит оба элемента. Боб может быть доступен как bob
или people[0]
. Доступ к Ларри можно получить как people[1]
, а затем, при желании, кешировать и получить к нему доступ как larry
(или любой другой) после этого.
ОК, хорошо. Но иногда метод не должен передаваться новому объекту. Взять, к примеру, Array.Sort<T>
. Следующее не имеет большого смысла:
Array.Sort<int>(new int[] {5, 6, 3, 7, 2, 1});
Весь приведенный выше код - это взять новый массив, отсортировать его и затем забыть о нем (поскольку счетчик ссылок достигает нуля после выхода из Array.Sort<int>
, и поэтому отсортированный массив будет собираться мусором, если я не ошибаюсь) , Так что Array.Sort<T>
ожидает «существующий» массив в качестве аргумента.
Возможно, есть и другие методы, которые могут ожидать"новых" объектов (хотя я бы вообще подумал, что иметь такое ожидание было бы ошибкой проекта). Несовершенный пример будет следующим:
DataTable firstTable = myDataSet.Tables["FirstTable"];
DataTable secondTable = myDataSet.Tables["SecondTable"];
firstTable.Rows.Add(secondTable.Rows[0]);
Как я уже сказал, это не лучший пример, поскольку DataRowCollection.Add
на самом деле не ожидает new DataRow
, точно; но ожидает DataRow
, который еще не принадлежит DataTable
. Так что последняя строка в коде выше не будет работать; должно быть:
firstTable.ImportRow(secondTable.Rows[0]);
Во всяком случае, это большая настройка для моего вопроса, а именно: есть ли способ применить политику «только новые объекты» или «только существующие объекты» для параметров метода , либо в его определении (возможно, по некоторым пользовательским атрибутам, о которых я не знаю) или в самом методе (возможно, по отражению, хотя я бы, вероятно, уклонился от этого, даже если бы он был доступен)?
Если нет, то любые интересные идеи относительно того, как возможно достичь этого, будут более чем приветствоваться. Например, я полагаю, если бы был какой-то способ получить счетчик ссылок GC для данного объекта, вы могли бы сразу сказать в начале метода, получили ли вы новый объект или нет (при условии, что вы имеете дело со ссылочными типами конечно, - это единственный сценарий, к которому этот вопрос относится в любом случае).
EDIT
Более длинная версия становится длиннее.
Хорошо, предположим, у меня есть какой-то метод, который я хочу опционально принять TextWriter
для вывода его прогресса или что-у-вас:
static void TryDoSomething(TextWriter output) {
// do something...
if (output != null)
output.WriteLine("Did something...");
// do something else...
if (output != null)
output.WriteLine("Did something else...");
// etc. etc.
if (output != null)
// do I call output.Close() or not?
}
static void TryDoSomething() {
TryDoSomething(null);
}
Теперь давайте рассмотрим два разных способа, которыми я мог бы вызвать этот метод:
string path = GetFilePath();
using (StreamWriter writer = new StreamWriter(path)) {
TryDoSomething(writer);
// do more things with writer
}
OR
TryDoSomething(new StreamWriter(path));
Хм ... может показаться, что это создает проблему, не так ли? Я создал StreamWriter
, который реализует IDisposable
, но TryDoSomething
не собирается предполагать, знает ли он эксклюзивный доступ к своему аргументу output
или нет. Таким образом, объект либо преждевременно удаляется (в первом случае), либо вообще не удаляется (во втором случае).
Я не говорю, что это будет отличный дизайн, обязательно. Возможно, Джош Стодола прав, и это просто плохая идея с самого начала. Во всяком случае, я задал вопрос главным образом потому, что мне было просто любопытно, возможно ли такое . Похоже, ответ: не совсем.