Holy goodness, did you guys ever find a lot of additional ways in which an "eliminate variable" refactoring can go wrong. Just a few of your observations: (again, in every case, "x" is eliminated.)
Any situation in which x is being treated as a variable rather than a value will pose a problem. Some obvious ones, like if x is on the left side of an assignment, or the target of a ++, or used as a "ref" or "out" parameter are straightforward. But there are some situations in which it is a bit surprising where x is being used as a variable. Suppose S is a mutable struct with field F:
S x = new S();
x.F = 123;
Here we cannot simply say (new S()).F = 123 because new S() is not a variable. The mutable field requires a storage location to mutate but we don't have a storage location here.
A number of people pointed out that the C# rules about how simple names may be used potentially pose problems:
int y = 2;
void M()
{
Action x = () => { Console.WriteLine(y); }; // refers to this.y
{
string y = "hello";
x();
}
The two inconsistent uses of the simple name y are legal here because the declaration spaces in which both are first used do not overlap. But the refactoring causes them to overlap; this needs to be refactored to
void M()
{
{
string y = "hello";
((Action)(()=>{Console.WriteLine(this.y);})))();
}
It gets even worse if the inconsistent simple names cannot be fully qualified:
Action x = () => {int z = 123;};
{
string z = "hello";
x();
}
Now one of the local zeds must be renamed if the refactoring is to succeed.
Read more: Fabulous Adventures In Coding
Any situation in which x is being treated as a variable rather than a value will pose a problem. Some obvious ones, like if x is on the left side of an assignment, or the target of a ++, or used as a "ref" or "out" parameter are straightforward. But there are some situations in which it is a bit surprising where x is being used as a variable. Suppose S is a mutable struct with field F:
S x = new S();
x.F = 123;
Here we cannot simply say (new S()).F = 123 because new S() is not a variable. The mutable field requires a storage location to mutate but we don't have a storage location here.
A number of people pointed out that the C# rules about how simple names may be used potentially pose problems:
int y = 2;
void M()
{
Action x = () => { Console.WriteLine(y); }; // refers to this.y
{
string y = "hello";
x();
}
The two inconsistent uses of the simple name y are legal here because the declaration spaces in which both are first used do not overlap. But the refactoring causes them to overlap; this needs to be refactored to
void M()
{
{
string y = "hello";
((Action)(()=>{Console.WriteLine(this.y);})))();
}
It gets even worse if the inconsistent simple names cannot be fully qualified:
Action x = () => {int z = 123;};
{
string z = "hello";
x();
}
Now one of the local zeds must be renamed if the refactoring is to succeed.
Read more: Fabulous Adventures In Coding