I'm writing a c# program that will launch many child processes. At some time later on, I'll need to retrieve those processes by ID and then match those processes to a set of processes stored in a Dictionary that were added to the Dictionary when they were first created. However, I'm running into a problem that seems like pure ridiculousness...
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'
I've used .NET Reflector to find out that GetProcessById returns a 'new Process(...)', but it seems like it should just find a reference to the already running process and return it instead.
You can assume the first Debug statement is essentially a call like
MyCustomDataType data = myDictionary[notepad];
I would expect to get the data I originally inserted, instead I get a KeyNotFoundException probably because the default comparer is doing a reference check. To counter this, I've added a custom IComparer on my dictionary that just checks that the two Process objects have the same ID, so I can get the associated data as expected. However, this has its own problem in tha开发者_如何学运维t Processes that are not running do not have process IDs, so sometimes the call in my custom IComparer to Process.ID throws an InvalidOperationException!!! So, I've fixed one problem only to create another.
So, I guess I have two questions:
- Why doesn't .NET just return a reference to an already running Process instance?
- What can I do to match processes stored in my dictionary since using process ID is not always valid for the lifetime of the Process object?
Not really sure why you had to resort to Reflector, since the GetProcessByID
MSDN documentation clearly states:
Creates a new Process component, and associates it with the existing process resource that you specify.
The framework can't return to you the same instance you have. To be able to do this, the framework would have to keep a reference to all Process instances ever created and compare the process ID for them to find out the one you already have. I'll leave to you to imagine the implications this would have on the memory and the perf of the framework.
Besides, the Process class is a wrapper around the process handle returned by the OpenProcess
Win32 API. And it is possible to have multiple handles to the same process. And input/output redirection can be done on a per-handle basis, thus, it is expected scenario to be able to have two Process instances that represent the same process and one of them dealing with the output and error streams and the other one with the input stream.
On a separate note, it seems to me that you are using the Process object itself as the key for the Dictionary. But the Process object does not represent the identity of the actual process, it is just a representation of the process. You should use as a key something that represents the identity of the process instead.
Running programs are operating system processes, not instances of the Process managed type. The Process
type is one type of managed wrapper object around an operating system concept. It allows control of the target process by hiding the P/Invoke calls. The operating system does not require a particular instance of the Process class perform these operations, which is why GetProcessById
can return a new instance and still expect everything to work.
The ID is valid for the life of the process itself. Perhaps you could set EnableRaisingEvents to true and add an event handler to the Process.Exited event that removes the process from your cache?
1) Your first question is analogous to:
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
Nothing is keeping track of created List<string>
's which is the same for created Process
's
2) I suggest you don't store Process
in the dictionary and instead create another class that stores the process id and the Process
references and does something intelligent when the process that the Process
refers to isn't running anymore.
What would you want .net to do, in this case?
1st Executable
Process notepad = new Process();
notepad.StartInfo.FileName = "notepad";
notepad.Start();
Assume that you know the processId of the notepad instance.
In the 2nd executable, you would want to get hold of that process using the Id
2nd Executable
Process n2 = Process.GetProcessById(notepadIdInputByUser);
Object reference comparison can be done within an application, provided the object construction is in your hand (as against the operating system).
How will .net get you the instance of Process from the 1st Executable into the 2nd Exectuable?
EDIT: ALthough Process
is a class, it cannot be reference compared.
It acts like a struct
, where you could do member comparison.
Use ProcessId as key of your dictionary.
Don't be afraid to create a new instance of Process using GetProcessById every time you need it. It's a lightweight object and garbage collector will clean up for you.
精彩评论