Reputation: 949
How can I achieve something like this?
public class BlaBlaBla
{
private PotatoesContainer _containerField;
private bool _booleanField;
private ref T GetBackingFieldRef<T>(string propertyName)
{
if (string.IsNullOrWhiteSpace(propertyName))
throw new ArgumentNullException(nameof(propertyName));
if (propertyName == "BooleanProperty")
return ref _booleanField;
else if (propertyName == "ContainerProperty")
return ref _containerField;
throw new ArgumentException("Property does not exist", nameof(propertyName));
}
public void ManageProperty<T>(string propertyName, T newValue)
{
//Check stuff;
var referenceToField = GetBackingFieldRef<T>(propertyName);
referenceToField = newValue;
}
}
I searched in all ref documentation and I cannot see anything. And I cannot cast calling (T)
.
Is this possible?
Is there some other way (with Action
, Func
or something)?
Upvotes: 0
Views: 196
Reputation: 23721
It's doable (as are most things), if you resort to using unsafe code. I would agree with the commenters that this is a bad idea and there are plenty of better ways to achieve what you're trying to do. However for educational purposes, here goes anyway:
using System.Runtime.CompilerServices;
...
public unsafe ref T GetBackingFieldRef<T>(string propertyName)
{
if (string.IsNullOrWhiteSpace(propertyName))
throw new ArgumentNullException(nameof(propertyName));
switch (propertyName)
{
case "BooleanProperty" when typeof(T) == typeof(bool):
return ref Unsafe.AsRef<T>(Unsafe.AsPointer(ref _booleanField));
case "ContainerProperty" when typeof(T) == typeof(PotatoesContainer):
return ref Unsafe.AsRef<T>(Unsafe.AsPointer(ref _containerField));
default:
throw new ArgumentException("Property does not exist or type mismatch", nameof(propertyName));
}
}
This uses Unsafe.AsPointer<T>()
and Unsafe.AsRef<T>()
to allow the otherwise difficult conversion to ref T
. There's some checking of types to ensure that the type of T
matches the type of the backing field, but this is of course very fragile - if you change the type of a backing field you'll have to remember to change the type checks, and will have to manually find all the calls to GetBackingFieldRef<T>()
for that field and update them otherwise you'll get exceptions and/or memory corruption at runtime.
Upvotes: 1