DrkDeveloper
DrkDeveloper

Reputation: 949

Return reference of generic

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

Answers (1)

Iridium
Iridium

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

Related Questions