Closed boformer closed 9 years ago
I have not looked into that and I am currently quite busy. I will happily take a look at that as soon as I have the time, but I doubt that there is a simple solution.
The first problem that comes to mind is this: If you patch the virtual function table, you have to do it for each class that overrides the method in question. That is problematic because in effect you would have to monitor all assemblies that are loaded at any time and go through all the classes and apply the redirection. (That's not hard, but it requires some more effort.) But if you are doing this, then you could just as well redirect the method itself in each of the child-classes. An alternative approach may be to patch all call-sites of the virtual function, but I'd argue that this is much harder.
But if you are doing this, then you could just as well redirect the method itself in each of the child-classes.
Yep, that would be just fine.
But this is quite straight-forward and should be possible using just reflection. So may I consider this issue resolved?
Hmm, can you give an example?
How can I replace a virtual method of a class (extending is not an option)?
My point was that if you know all classes that derive from your target class and override the virtual method in question, then you could simply patch the methods in the subclass (where the patching is done with the code from the repository). If you do not know the classes that override your target method, you can crawl through the assemblies currently loaded and check every type. (You should also check for assemblies that are (re)loaded during runtime.) Coming to think about it, you do not have much of a choice: Subclassing is inherently open, so going over all types in all assemblies seems like the only safe thing to do.
where the patching is done with the code from the repository
The problem is that it does not seem to work for methods tagged as virtual or override. The RedirectionHelper only works for sealed methods. That's why I was asking.
Works fine for me.
Test setup:
public class TestClass
{
public virtual void TestMethod()
{
DebugLog.Log("TestClass.TestMethod");
}
public void Detour()
{
DebugLog.Log("TestClass.Detour");
}
}
public class TestSubClass : TestClass
{
public override void TestMethod()
{
DebugLog.Log("TestSubClass.TestMethod");
}
public void DetourSub()
{
DebugLog.Log("TestSubClass.DetourSub");
}
}
Test code:
TestClass obj = new TestClass();
TestSubClass subObj = new TestSubClass();
RedirectionHelper.RedirectCalls(typeof(TestClass).GetMethod("TestMethod"), typeof(TestClass).GetMethod("Detour"));
subObj.TestMethod();
RedirectionHelper.RedirectCalls(typeof(TestSubClass).GetMethod("TestMethod"), typeof(TestSubClass).GetMethod("DetourSub"));
obj.TestMethod();
subObj.TestMethod();
Prints out:
TestSubClass.TestMethod
TestClass.Detour
TestSubClass.DetourSub
As I said, you have to do the detour manually for each subclass. This seems inevitable because the superclass can hardly now all its subclasses -- inheritance is inherently open.
Thanks for the clarification. Your detour method is really helpful!
Do you know a way to detour virtual methods? Maybe by modifying the virtual method table?
Your RedirectionHelper class is one of the most powerful tools for Skylines Modding. A virtual method detour would make it perfect.