Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WinForms, .Net Framework Новый топик    Ответить
 инфо по закрытым полям автореализованных свойств  [new]
felix_ff
Member

Откуда: Moscow
Сообщений: 1914
доброго времени,

чето туплю но разыгрался академический интерес:

можем мы как либо с помощью отражения или еще каких либо плясок с бубнами выйти на имя поля автореализованного свойства?

то есть к примеру:
public class foo {

public string Name1 {get; set;}
public string Name2 {get;}
private string Name3 {get;}


public static KeyValuePair<string, string> GetInfo(object t) {
    //какая то магия которая вернет список вида:
    // item[0]: { Name1, <Name1>k_BackingField }
    // item[1]: { Name2, <Name2>k_BackingField }
    // item[2]: { Name3, <Name3>k_BackingField }
}

}


сборка строки вида PropertyName + "k_BackingField" не устроит ибо боюсь что нет гарантии что когда нибудь "k_" не станет "l_"

Сообщение было отредактировано: 24 сен 21, 01:02
24 сен 21, 01:10    [22375195]     Ответить | Цитировать Сообщить модератору
 Re: инфо по закрытым полям автореализованных свойств  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 6257
felix_ff
можем мы как либо с помощью отражения или еще каких либо плясок с бубнами выйти на имя поля автореализованного свойства?

Нет.
К примеру, у меня есть самописное свойство с backing field:
bool [имя_поля];
public bool SomeProperty => [имя поля];

- сможете угадать, как на самом деле называется [имя поля]?
Рихтер, помнится, наезжал на auto-implemented properties в т.ч. по той причине, что они с очередным релизом фреймворка могут сломать бинарную сериализацию - она сериализует backing fields этих свойств, а очередной релиз может поменять схему именования полей.
Так что в данном случае - только полагаться на эмпирику по составлению наименования этих backing fields.
Еще, как вариант, можно задействовать Mono.Cecil, и распарсить IL тело аксессора свойства:
namespace test2
{
  class Program
  {
    static void Main()
    {
      using (var fs = new FileStream(typeof(Foo).Assembly.Location, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
      {
        var assembly = AssemblyDefinition.ReadAssembly(fs);
        var toInspect = assembly.MainModule
          .GetTypes()
          .Single(t => "test2.Foo".Equals(t.FullName, StringComparison.Ordinal))
          .Methods
          .Single(m=> m.HasBody && m.IsGetter && "get_Bar".Equals(m.Name, StringComparison.Ordinal));
        foreach (var instruction in toInspect.Body.Instructions)
          Console.WriteLine($"{instruction.OpCode} \"{instruction.Operand}\"");
      }
  }

  class Foo
  {
    public Foo(string bar) => Bar = bar;
    public string Bar { get; }
  }
}

В консоли будет

ldarg.0 ""
ldfld "System.String test2.Foo::<Bar>k__BackingField"
ret ""
24 сен 21, 06:12    [22375209]     Ответить | Цитировать Сообщить модератору
 Re: инфо по закрытым полям автореализованных свойств  [new]
felix_ff
Member

Откуда: Moscow
Сообщений: 1914
Сон Веры Павловны,

да соглсаен, проспался и понял что занимался ерундой.

у нас же никто не гарантирует что там за кулисами именно поле:

public class foo {
  private _d1 double;
  private _d2 double;

  public double Value {
     get { return _d1 / _d2; }
     set { Calculator.Calculate(out _d1, out d2, value );}
  }
}


я кстати и озаботился этим вопросом собственно разбираясь с сериализацией, (правда xml) но суть проблемы таже
в случае если к примеру у нас есть закрытое приватное автосвойство только с аксессором get как в таком случае десериализовать объект? (с сериализацией все норм)

public class foo {
    private int _myValue {get;}
    public foo(int value) {_myValue = value}
    
}


Сообщение было отредактировано: 24 сен 21, 11:15
24 сен 21, 11:21    [22375262]     Ответить | Цитировать Сообщить модератору
 Re: инфо по закрытым полям автореализованных свойств  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 6257
felix_ff
я кстати и озаботился этим вопросом собственно разбираясь с сериализацией, (правда xml) но суть проблемы таже
в случае если к примеру у нас есть закрытое приватное автосвойство только с аксессором get как в таком случае десериализовать объект? (с сериализацией все норм)

Тут только делать самописную сериализацию. Стандартная XML-сериализация вообще имеет жесткие ограничения, в частности:
1. Класс должен быть public, non-nested, и иметь public-конструктор без параметров;
2. Сериализуемые свойства должны быть public, должны иметь оба акссесора (и get, и set), и оба эти аксессора должны быть public.
И поэтому она часто неудобна.
Десериализация по полям с закрытыми сеттерами - ну, тут или рефлекшн (что медленно), или можно посмотреть, как это сделано в Dapper - он вполне умеет делать это. Вроде как там это реализовано через Reflection.Emit.
24 сен 21, 11:58    [22375278]     Ответить | Цитировать Сообщить модератору
 Re: инфо по закрытым полям автореализованных свойств  [new]
felix_ff
Member

Откуда: Moscow
Сообщений: 1914
Сон Веры Павловны

Тут только делать самописную сериализацию. Стандартная XML-сериализация вообще имеет жесткие ограничения, в частности:
...
И поэтому она часто неудобна.


да согласен, но она позволяет использовать реализацию IXmlSerializable что по сути дает возможности той же бинарной сериализации.

Десериализация по полям с закрытыми сеттерами - ну, тут или рефлекшн (что медленно), или можно посмотреть, как это сделано в Dapper - он вполне умеет делать это. Вроде как там это реализовано через Reflection.Emit.


тут проблема именно в том что закрытого сеттера на свойстве нет. если смотреть MethodInfo по свойству видно что getMethod есть, а setMethod = null;

любой вызов из Reflection.InvokeMember / SetValue вызывает исключение ArgumentException: property set mthod not found. что и логично, поскольку установить значение можно только в конструкторе, или явно задав значение backing полю.

этот пример явно притянут за уши, и я понимаю что по факту свойство должно тогда бы было объявляться как
  private int Value {get; private set; } 


и проблемы бы не было, но как я уже сказал чисто академический интерес разыгрался: "а что если вот так" :)


Про Dapper, сейчас покопаюсь проверю может ли он десиреализовавать такие конструкции, если получится покопаюсь в кишках, спасибо
24 сен 21, 12:30    [22375287]     Ответить | Цитировать Сообщить модератору
 Re: инфо по закрытым полям автореализованных свойств  [new]
felix_ff
Member

Откуда: Moscow
Сообщений: 1914
Да, посмотрел dapper там создается ILGenerator и начинается сборка динамического метода по метаданным класса. мудрено однако :)
24 сен 21, 14:35    [22375348]     Ответить | Цитировать Сообщить модератору
 Re: инфо по закрытым полям автореализованных свойств  [new]
Ролг Хупин
Member

Откуда: Чебаркуль
Сообщений: 4450
felix_ff,

"да соглсаен, проспался и понял что занимался ерундой."

а, так значит был не проспавшись, да и сейчас, судя по всему в таком же состоянии
24 сен 21, 16:55    [22375482]     Ответить | Цитировать Сообщить модератору
 Re: инфо по закрытым полям автореализованных свойств  [new]
petalvik
Member

Откуда:
Сообщений: 738
felix_ff
собственно разбираясь с сериализацией

Контракт и Соглашения - на этом всё держится.

Сон Веры Павловны
Стандартная XML-сериализация вообще имеет жесткие ограничения, в частности:
1. Класс должен быть public, non-nested, и иметь public-конструктор без параметров;
2. Сериализуемые свойства должны быть public, должны иметь оба акссесора (и get, и set), и оба эти аксессора должны быть public.

Вот это и есть описание соглашений по умолчанию.

Но можно задать и явный контракт. Например, с помощью атрибутов.


По аналогии следует делать и самописную сериализацию. Либо опираемся на некоторые соглашения: например, сериализуем только публичные свойства. Либо описываем некий контракт: навешиваем атрибуты на те члены, которые нужно сериализовать, или реализуем определённый интерфейс. Или задаём контракт ещё как-то: передаём в конструктор сериализатора список полей/свойств, например. Насочинять можно много.

В любом случае, повторюсь ещё раз, есть либо неявные соглашения (но они всё равно явно описаны в документации используемого сериализатора), либо явно заданный контракт.
А опираться на BackingField действительно не стоит. Оно и под соглашения не попадает и контрактом не является.


P. S. Почему практически всегда, когда говорят о XML-сериализации, имеют в виду XmlSerializer? Семейство DataContractSerializer'ов имеет свои достоинства. Serialization guidelines - авось кому пригодится.
29 сен 21, 07:58    [22377203]     Ответить | Цитировать Сообщить модератору
 Re: инфо по закрытым полям автореализованных свойств  [new]
felix_ff
Member

Откуда: Moscow
Сообщений: 1914
petalvik,

тут та же проблема, при сериализации автореализованного свойства только с методом акссесором get при использовании DataContractSerializer будет ругаться что у свойства нет метода set, это документированно.

но представим себе ситуацию что нужно реализовать сериализацию такого класса:

public class foo {
   public string Name1 {get;set;}
   private string Name2 {get;}

   public foo(){
     Name2 = Guid.NewGuid().ToString();
   } 
}


при этом воссоздать оба свойства.

Сообщение было отредактировано: 1 окт 21, 19:12
1 окт 21, 19:22    [22378599]     Ответить | Цитировать Сообщить модератору
 Re: инфо по закрытым полям автореализованных свойств  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 4283
felix_ff
petalvik,

тут та же проблема, при сериализации автореализованного свойства только с методом акссесором get при использовании DataContractSerializer будет ругаться что у свойства нет метода set, это документированно.

но представим себе ситуацию что нужно реализовать сериализацию такого класса:

public class foo {
   public string Name1 {get;set;}
   private string Name2 {get;}

   public foo(){
     Name2 = Guid.NewGuid().ToString();
   } 
}


при этом воссоздать оба свойства.

какая то ересь, приватное поле? ну допустим, если бы в нем была логика, я бы еще поверил, но лучше использовать просто метод и приватное поле. Это и по скорости лучше. Если поле приватное, не кто не может его менять кроме самого этого класса и точка.
Меня лично, это вполне устраивает, это основы ООП, так сказать заповедь.
Вот с конструкторами, это да, подстава, но классы моделей обычно не имеют конструктора вообще, дефолтный и им норм, другие классы обычно не стерилизуют, если только в каких то особых случаях. Вообще по факту, такие вещи лучше начинать с xsd схемы, потом генерировать модель налету или, что сейчас модно, молодёжно?
1 окт 21, 21:41    [22378631]     Ответить | Цитировать Сообщить модератору
Все форумы / WinForms, .Net Framework Ответить