C
C#2mo ago
CyberBotX

Is it possible to use Reflection to replace a static readonly field without the static constructor?

So, say for example I have a class like the following:
class Test
{
static readonly string Value = throw new NotImplementedException();
}
class Test
{
static readonly string Value = throw new NotImplementedException();
}
Obviously, trying to use that class will result in a TypeInitializationException being thrown. I had thought to use Reflection to do something like this:
typeof(Test).GetField("Value", BindingFlags.NonPublic | BindingFlags.Static)!.SetValue(null, "TestValue");
typeof(Test).GetField("Value", BindingFlags.NonPublic | BindingFlags.Static)!.SetValue(null, "TestValue");
(The exception is thrown when SetValue is called, not when GetField is called.) But this results in the type being initialized and thus the same exception is thrown. I know that trying to do something like this is probably frowned upon, but I am trying to get around an issue in an externally generated class that I'd rather not modify (despite that I could in this case) just in case I have to re-generate the file again. So is there any way around this to be able to replace the value of that static readonly field without the static constructor being called and thus throw an exception?
20 Replies
Angius
Angius2mo ago
despite that I could in this case
Then do. Anything else will just be a dirty half-working volatile workaround Assuming you can find a workaround at all
CyberBotX
CyberBotX2mo ago
OK, so I could, yes, but then I would lose the changes I make if I regenerate the class from the external tool that generated it in the first place. So I'd rather not have to remember to replace that code every single time I regenerate the class, I'm more likely to forget to do so than remember to do so.
Angius
Angius2mo ago
Ah, well, that's some garbage tool you're using, then
Ploot
Ploot2mo ago
I feel like the better approach would be to look into ways to stop the tool generating such code in the first place
Angius
Angius2mo ago
:This_rrc:
CyberBotX
CyberBotX2mo ago
I have absolutely no control over that part of its output. The tool in question is the Hime parsing generator in this case. I can't tell it not to do what it is doing, the only way I probably could would probably be to fork the tool and edit the tool, and that sounds very undesirable (especially since the tool is written in Rust and I don't know Rust).
Angius
Angius2mo ago
I'd raise them an issue for sure To answer your question, though, nothing can be done, not even with reflections throwing in an assignment to a field is a syntax error Does this code even compile in the first place?
CyberBotX
CyberBotX2mo ago
The file does compile, yes. The error is a runtime error, not a compile error. The actual generated code is looking for a file in the project's resources, while I'd rather change it so it just accesses a file directly. Plus, the error from my use of Reflection happens when I call SetValue and it is because the static constructor gets called before it can set the value, which I understand is how things would normally work. But if nothing can be done, then that's fine, I'll just have to edit the class and hope I remember to do so every time, even if that is error-prone.
Angius
Angius2mo ago
I guess you could try source generators There is a way to rewrite a bit of code, when you know the exact position that should be rewritten You could do, basically, the equivalent to
theClass.Write(2, 4, "static readonly string Value = \"boo\"");
theClass.Write(2, 4, "static readonly string Value = \"boo\"");
https://andrewlock.net/exploring-the-dotnet-8-preview-changing-method-calls-with-interceptors/
CyberBotX
CyberBotX2mo ago
So, as I mentioned at the start, the call to GetField isn't a problem, because that doesn't cause the constructor to run. It is when SetValue is called that is the problem, because it does cause the constructor to run. Although I've since decided to make this a non-issue as I have decided not to bother using the code now.
canton7
canton72mo ago
But... It's not a technical solution It doesn't work. And if you read the question, you'd understand why
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
reflectronic
reflectronic2mo ago
anyway, you can’t do it even if there was no static constructor reflection does not allow you to set static readonly fields cannot be done
TizzyT
TizzyT2mo ago
you can throw from a field like that?
TizzyT
TizzyT2mo ago
Maybe you can inherit that class and hide the field?
No description
TizzyT
TizzyT2mo ago
It wont change the actual value of the original tho
Angius
Angius2mo ago
You cannot, that's the issue
TizzyT
TizzyT2mo ago
but didnt he reply yes to this? o wells, im lost and doesnt look like this is going to be resolved
CyberBotX
CyberBotX2mo ago
The code I put up above was an example, not literally what was being done. The actual code was calling a method which would eventually throw an exception.
MODiX
MODiX2mo ago
If you have no further questions, please use /close to mark the forum thread as answered
Want results from more Discord servers?
Add your server