Информация об изменениях

Сообщение Re[35]: Welcome to C# 9.0 от 18.09.2020 11:17

Изменено 18.09.2020 12:12 artelk

Re[35]: Welcome to C# 9.0
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Здравствуйте, artelk, Вы писали:


A>>Так что вполне можно было сделать так, что десериализация в иммутабельный рекорд (и класс с init-only свойствами) работала бы без проблем.


НС>Нельзя. Я тебе еще раз напомню, что нормальные десериализаторы не через рефлексию работают.


А FieldInfo/PropertyInfo они откуда берут? Для кодогеренации они тоже нужны.
Кстати, вот попробовал с SRE:
public delegate void ClassFieldSetter<in T, in TValue>(T target, TValue value) where T : class;

public static class FieldSetterCreator
{
    public static ClassFieldSetter<T, TValue> CreateClassFieldSetter<T, TValue>(FieldInfo field)
        where T : class
    {
        return CreateSetter<T, TValue, ClassFieldSetter<T, TValue>>(field);
    }

    private static TDelegate CreateSetter<T, TValue, TDelegate>(FieldInfo field)
    {
        return (TDelegate)(object)CreateSetter(field, typeof(T), typeof(TValue), typeof(TDelegate));
    }

    private static Delegate CreateSetter(FieldInfo field, Type instanceType, Type valueType, Type delegateType)
    {
        var paramType = instanceType.IsValueType ? instanceType.MakeByRefType() : instanceType;
        var setter = new DynamicMethod("", typeof(void),
                                        new[] { paramType, valueType },
                                        field.DeclaringType.Module, true);

        var generator = setter.GetILGenerator();
        generator.Emit(OpCodes.Ldarg_0);
        generator.Emit(OpCodes.Ldarg_1);
        generator.Emit(OpCodes.Stfld, field);
        generator.Emit(OpCodes.Ret);
        return setter.CreateDelegate(delegateType);
    }
}

public class Foo
{
    private readonly int x;
    public int X => x;
}

class Program
{
    static void Main()
    {
        var x = typeof(Foo).GetField("x", BindingFlags.Instance | BindingFlags.NonPublic);
        var setX = FieldSetterCreator.CreateClassFieldSetter<Foo, int>(x);
        var foo = new Foo();
        setX(foo, 42);
        Console.WriteLine(foo.X); // 42!
    }
}

readonly на поле успешно проигнорировался.
Re[35]: Welcome to C# 9.0
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Здравствуйте, artelk, Вы писали:


A>>Так что вполне можно было сделать так, что десериализация в иммутабельный рекорд (и класс с init-only свойствами) работала бы без проблем.


НС>Нельзя. Я тебе еще раз напомню, что нормальные десериализаторы не через рефлексию работают.


А FieldInfo/PropertyInfo они откуда берут? Для кодогеренации они тоже нужны.
Кстати, вот попробовал с SRE:
public delegate void ClassFieldSetter<in T, in TValue>(T target, TValue value) where T : class;

public static class FieldSetterCreator
{
    public static ClassFieldSetter<T, TValue> CreateClassFieldSetter<T, TValue>(FieldInfo field)
        where T : class
    {
        return CreateSetter<T, TValue, ClassFieldSetter<T, TValue>>(field);
    }

    private static TDelegate CreateSetter<T, TValue, TDelegate>(FieldInfo field)
    {
        return (TDelegate)(object)CreateSetter(field, typeof(T), typeof(TValue), typeof(TDelegate));
    }

    private static Delegate CreateSetter(FieldInfo field, Type instanceType, Type valueType, Type delegateType)
    {
        var setter = new DynamicMethod("", typeof(void), new[] { instanceType, valueType }, field.DeclaringType.Module, true);
        var generator = setter.GetILGenerator();
        generator.Emit(OpCodes.Ldarg_0);
        generator.Emit(OpCodes.Ldarg_1);
        generator.Emit(OpCodes.Stfld, field);
        generator.Emit(OpCodes.Ret);
        return setter.CreateDelegate(delegateType);
    }
}

public class Foo
{
    private readonly int x;
    public int X => x;
}

class Program
{
    static void Main()
    {
        var x = typeof(Foo).GetField("x", BindingFlags.Instance | BindingFlags.NonPublic);
        var setX = FieldSetterCreator.CreateClassFieldSetter<Foo, int>(x);
        var foo = new Foo();
        setX(foo, 42);
        Console.WriteLine(foo.X); // 42
    }
}

readonly на поле успешно проигнорировался.