2009-12-17 5 views
3

Я пишу программу C#, которая запустит многие дочерние процессы. Через некоторое время мне нужно будет восстановить эти процессы по идентификатору, а затем сопоставить эти процессы с набором процессов, хранящихся в словаре, которые были добавлены в словарь при их создании. Тем не менее, я бегу в проблему, которая, кажется, как чистая нелепость ....NET Frustration - Process.GetProcessById возвращает новую ссылку

Process notepad = new Process(); 
notepad.StartInfo.FileName = "notepad"; 
notepad.Start(); 

Process n2 = Process.GetProcessById(notepad.Id); 

Debug.WriteLine(notepad == n2);  //'False', but Why isn't this true??? 
Debug.WriteLine(notepad.Id == n2.Id); //'True' 

Я использовал .NET Reflector, чтобы узнать, что GetProcessById возвращает «новый процесс (...)», но похоже, что он должен просто найти ссылку на уже запущенный процесс и вернуть его вместо этого.

Можно предположить, первый оператор Debug, по существу, вызов, как

MyCustomDataType данных = MyDictionary [блокнота];

Я бы ожидал получить данные, которые я первоначально вставил, вместо этого я получаю исключение KeyNotFoundException, вероятно, потому, что по умолчанию сопоставитель выполняет контрольную проверку. Чтобы противостоять этому, я добавил пользовательский IComparer в свой словарь, который просто проверяет, что оба объекта процесса имеют одинаковый идентификатор, поэтому я могу получить связанные данные, как ожидалось. Однако у этого есть своя проблема в том, что Процессы, которые не работают, не имеют идентификаторов процесса, поэтому иногда вызов в моем обычном IComparer для Process.ID вызывает InvalidOperationException !!! Итак, я исправил одну проблему только для создания другой.

Так что, я думаю, у меня есть два вопроса:

  • Почему не .NET просто возвращает ссылку на уже запущенный экземпляр процесса?
  • Что я могу сделать, чтобы сопоставить процессы, хранящиеся в моем словаре, поскольку идентификатор процесса не всегда действителен для срока службы объекта Process?

ответ

2

Запуск программ - это процессы операционной системы, а не экземпляры управляемого процесса. Тип Process - это один тип управляемого объекта оболочки вокруг концепции операционной системы. Он позволяет контролировать целевой процесс, скрывая вызовы P/Invoke. Операционная система не требует, чтобы конкретный экземпляр класса Process выполнял эти операции, поэтому GetProcessById может возвращать новый экземпляр и все еще ожидать, что все будет работать.

Идентификатор действителен для жизни самого процесса. Возможно, вы могли бы установить EnableRaisingEvents в true и добавить обработчик события в событие Process.Exited, которое удалит процесс из вашего кеша?

2

Что бы вы хотели .net сделать в этом случае?

первый Исполняемые

Process notepad = new Process(); 
notepad.StartInfo.FileName = "notepad"; 
notepad.Start(); 

Предположим, что вы знаете ProcessId из блокнота экземпляра.
Во 2 исполняемом, вы хотели бы, чтобы овладеть этот процесс с помощью Id

2nd Исполняемых

Process n2 = Process.GetProcessById(notepadIdInputByUser); 

Объекта ссылки сравнение может быть сделано в рамках приложения, при условии, что строительство объекта находится в вашей руке (в отличие от операционной системы).

Как будет .net получить экземпляр процесса от 1-го исполнимого до второго Exectuable?

РЕДАКТИРОВАТЬ: Хотя Process - это класс, его нельзя сравнивать по ссылке.
Он действует как struct, где вы можете сравнить элементы.

2

1) Ваш первый вопрос аналогичен:

var a = new List<string>{"one", "two", "three"}; 
var b = new List<string>{"one", "two", "three"}; 

if(a == b) { Debug.WriteLine("awesome"); } // not going to happen 

Ничего держит след созданных List<string>-х, который является одинаковым для созданных Process 's

2) Я предлагаю вам не магазин Process в словаре и вместо этого создайте другой класс, в котором хранятся идентификатор процесса и ссылки Process, и делает что-то интеллектуальное, когда процесс, который ссылается Process, больше не работает.

5

Не совсем уверен, почему вы вынуждены были прибегнуть к рефлектора, так как MSDN документация GetProcessByID ясно сказано:

Создает новый компонент процесса, и связывает его с существующим процесса ресурса, который вы укажете.

Рамка не может вернуть вам тот же экземпляр, который у вас есть. Чтобы иметь возможность сделать это, структура должна будет содержать ссылку на все экземпляры Процесса, когда-либо созданных, и сравнить идентификатор процесса для них, чтобы узнать тот, который у вас уже есть. Я оставлю вам представить себе последствия, которые это могло бы иметь для памяти и перформанса рамки.

Кроме того, класс Process является оберткой вокруг дескриптора процесса, возвращаемого API Win32 OpenProcess. И можно иметь несколько ручек для одного и того же процесса. И перенаправление ввода/вывода может быть выполнено для каждого элемента управления, поэтому ожидается, что сценарий будет иметь два экземпляра Процесса, которые представляют один и тот же процесс, и один из них имеет дело с потоками вывода и ошибок, а другой - с входной поток.

В отдельном примечании мне кажется, что вы сами используете объект Process как ключ для словаря. Но объект Process не представляет собой идентичность фактического процесса, это просто представление процесса. Вы должны использовать в качестве ключа то, что представляет собой идентичность процесса.

+0

Hi Franci. Большое спасибо за ваше четкое объяснение. Что бы вы порекомендовали «использовать в качестве ключа что-то, что представляет собой идентичность процесса»? Я не могу думать о какой-либо встроенной собственности, кроме ID. Кроме того, мне нужно свойство жить для жизни объекта Process независимо от того, запущен ли процесс или нет. – Chad

+0

идентификатор процесса представляет собой представление идентификатора f процесса. :-) Таким образом, ваш ключ должен быть идентификатором процесса. конечно, вы, очевидно, хотите сохранить связанный с ним объект Process и некоторые дополнительные данные, которые вы храните в текущем словаре. У вас есть опции - либо расширьте данные, хранящиеся в словаре, с помощью объекта «Процесс», и введите его идентификатором, либо добавьте второй словарь, в котором вы храните объекты «Процесс» с ключом по идентификатору. –

+1

Идентификаторы процессов (PID) не являются хорошим представлением идентичности процесса. Если процесс завершается, ОС может повторно использовать один и тот же PID для нового процесса позже. Кортеж идентификатора процесса и время начала процесса (для решения проблемы утилизации pid) - гораздо лучшая идентификация. –

0

Используйте ProcessId как ключ вашего словаря.

Не бойтесь создавать новый экземпляр процесса, используя GetProcessById каждый раз, когда вам это нужно. Это легкий объект, и сборщик мусора очистит вас.