Problem
I am working with an already existing library, to the source code of which I do not have access. This library represents an AST.
I want to copy parts of this AST, but rename references to variables in the process. Since there can be a AssignCommand-Object, which holds an Expression-object, I want to be able to copy each object with its own function, so I can call them recursively. However, since I do not have access to the code of the library, I cannot add a method such as CopyAndRename(string prefix).
Thus, my approach was to create a single function Rename with several overloads. Thus, I would have a family functions as follows:
public static Command Rename(Command cmd, string prefix)
public static AssignCommand Rename(AssignCommand cmd, string prefix)
public static AdditionExpressionRename(AdditionExpression expr, string prefix)
....
A function now consists of a List<Command>, where AssignCommand is a subclass of Command. I assumed that I could just pass a Command to the Rename-function and the runtime would find the most specific one. However, this is not the case and all commands are passed to Command Rename(Command cmd, string prefix). Why is this the case? Is there a way to delegate the call to the correct function without using ugly is-operations?
Minimal Example
I have broken this problem down to the following NUnit-Testcode
using NUnit.Framework;
public class TopClass{
    public int retVal;
}
public class SubClassA : TopClass{ }
[TestFixture]
public class ThrowawayTest {
    private TopClass Foo (TopClass x) {
        x.retVal = 1;
        return x;
    }
    private SubClassA Foo (SubClassA x) {
        x.retVal = 2;
        return x;
    }
    [Test]
    public void OverloadTest(){
        TopClass t = new TopClass();
        TopClass t1 = new SubClassA();
        SubClassA s1 = new SubClassA();
    t = Foo (t);
        t1 = Foo (t1);
        s1 = Foo (s1);
        Assert.AreEqual(1, t.retVal);
        Assert.AreEqual(2, s1.retVal);
        Assert.AreEqual(2, t1.retVal);
    }
}
So my question boils down to: "How can the test above be fixed in an elegant, polymorphic, object-oriented way without resorting to is-checks?"
Extension Methods
I have also tried using extension methods as follows. This did not solve the problem, since they are merely syntactical sugar for the approach above:
using NUnit.Framework;
using ExtensionMethods;
public class TopClass{
    public int retVal;
}
public class SubClassA : TopClass{ }
[TestFixture]
public class ThrowawayTest {
    private TopClass Foo (TopClass x) {
        x.retVal = 1;
        return x;
    }
    private SubClassA Foo (SubClassA x) {
        x.retVal = 2;
        return x;
    }
    [Test]
    public void OverloadTest(){
        TopClass t = new TopClass();
        TopClass t1 = new SubClassA();
        SubClassA s1 = new SubClassA();
        t.Foo(); s1.Foo(); t1.Foo();
        Assert.AreEqual(1, t.retVal);
        Assert.AreEqual(2, s1.retVal);
        Assert.AreEqual(2, t1.retVal);
    }
}
namespace ExtensionMethods{
    public static class Extensions {
        public static void Foo (this TopClass x) {
            x.retVal = 1;
        }
        public static void Foo (this SubClassA x) {
            x.retVal = 2;
        }
    }
}
 
     
     
     
     
     
    