To do this in general, you need a symbolic analysis of the values along all control paths, and boolean symbolic simplification to determine if the condition is true. For example:
void bar(...a) {
...
x=2*a;
if (...) x=17;
foo(x)
...
}
void foo(int x) {
if (x<a && !x>5) { // dead code if called from bar ...
...
To know that the dead code line is really dead, you have to find all calls
to foo and verify that each one causes this condition to occur. So you need
a global call graph, for which you need global function pointer analysis, for
which you need global and thus local points-to analysis...
I don't know any off-the-shelf tools that do this.
One could be built with some effort with a program transformation system. Our DMS Software Reengineering Toolkit has all of the mentioned machinery available for C.
While all this machinery isn't yet available for C#, it is implemented in largely a langauge agnostic way so getting there for C# is sweat but not impractical.