I have a C# .NET program that I believe has been compromised (reverse-engineered). Is there any way to prevent this?
Technically, there is no way to prevent something that has already happened, unless you have a time machine. Your question stated that you believe your program has been compromised (past perfect tense) -- this is an action which has already occurred. Preventing an action which has already occurred would involve time travel, because there is no other way that we can conceive of to do this.
The reason why this seemingly silly argument is relevant is that, even if you were to implement an obfuscation technique in your code today that makes it utterly impossible for anyone to ever reverse engineer your code again, it is still the case that at least one copy of your code without the obfuscation has already been released in some fashion, and has already been returned to a usable source format (or so you believe).
Since I don't know anyone on Earth who's ever created a working time machine, I doubt there is any possible way that you can properly handle this situation through technical means. If your software was freely available for download, then it is very likely that thousands or millions of people have copies of the unobfuscated binaries, and can at any time share those binaries between eachother and reverse engineer them at will. Even if you sold your software for a fee, if that fee wasn't extremely high, then it's probably already been reverse engineered by more than one person, whether paying customers or pirates.
You will probably have to resort to the only institution on Earth that can (in an extremely imperfect way) attempt to re-mediate erroneous or immoral actions which have occurred in the past: the legal system. You see, even if someone were doing something really nasty such as releasing a competing product using your code as a base, you don't strictly need a time machine to stop them from doing that: you can simply target the worst offenders with a lawsuit, and allow the justice system to play itself out. You won't necessarily get the ideal outcome, and you probably won't get all the money you're due (legal fees and all that); but it'll be better than sitting here wishing you had a time machine.
Of course, going forward, any new code developments you release should be obfuscated, if your goal is to prevent others from being able to conveniently reverse engineer the .NET assemblies. But I'll leave that topic to the other answerers; I just wanted to be a pedant.
You can't avoid it completely, but you can do something to make it more difficult for an attacker to do it, as explained in the following article: