malloc: *** ошибка освобождения указателя объекта не была выделена во время десериализации JSON - PullRequest
0 голосов
/ 10 января 2019

Я пытаюсь десериализовать строку JSON в список с помощью C # в Visual Studio для Mac для проекта Xamarin.Mac.

Я могу сериализовать без проблем с этим:

using (StreamWriter file = File.CreateText(filename))
            {
                var serializer = new JsonSerializer()
                {
                    Formatting = Formatting.Indented,
                    TypeNameHandling = TypeNameHandling.Auto,
                    TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple,
                    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                };
                await Task.Run(() => serializer.Serialize(file, contactroot));
            }

Но я получаю ошибку выше, когда пытаюсь десериализовать, используя это:

var contacts = JsonConvert.DeserializeObject<ContactRoot>(json);

Класс ContactRoot:

public class ContactRoot
{
    public List<Contact> contacts { get; set; }
}

Класс Contact наследует класс NSObject, необходимый для привязки к элементам управления в приложении Mac. Я бы тоже это включил, но есть более 70 свойств с несколькими атрибутами. Вот пара фрагментов из этого класса:

[Register("Contact")]
public class Contact : NSObject

... и много таких свойств:

public DateTime? updated_at { get; set; }

    [Export("updatedString"), Display(Name = "Updated Date"), Category("Misc"), Description("3"), DefaultValue(TypeOfValue.DateTime)]
    public string updatedString
    {
        get {
            if (this.updated_at.HasValue){
                return this.updated_at.Value.ToString();
            } else{
                return string.Empty;
            }
        }
        set
        {
            WillChangeValue("updatedString");
            try
            {
                if (!String.IsNullOrEmpty(value)) this.updated_at = Convert.ToDateTime(value);
            }
            catch (Exception)
            {
            }
            DidChangeValue("updatedString");
        }
    }

Я использую DateTime? потому что источник API требует этого, и поскольку привязка данных Xamarin, по-видимому, не обрабатывает значения NULL для int или DateTime, я использую строковое свойство для выполнения преобразования. Это прекрасно работает при использовании приложения, но не уверен, что это приводит к ошибке при десериализации. Я новичок в разработке для Mac, поэтому, наверное, что-то упустил.

EDIT

Ух, спасибо за быстрые ответы! Прежде чем увидеть какие-либо комментарии, я попробовал более простой класс, но получил тот же результат:

[Register("SimpleContact")]
public class SimpleContact : NSObject
{
    int _id = 0;
    string _first = String.Empty;
    string _last = String.Empty;

    [Export("id")]
    public int id {
        get { return _id; }
        set {
            WillChangeValue("id");
            _id = value;
            DidChangeValue("id");
        }
    }

    [Export("first")]
    public string first {
        get { return _first; }
        set {
            WillChangeValue("first");
            _first = value;
            DidChangeValue("first");
        }
    }

    [Export("last")]
    public string last
    {
        get { return _last; }
        set
        {
            WillChangeValue("last");
            _last = value;
            DidChangeValue("last");
        }
    }

    [Export("fullname")]
    public string fullname
    {
        get { return this.first + " " + this.last; }
    }

    public SimpleContact()
    {}

    public SimpleContact(int id, string first, string last)
    {
        this.id = id;
        this.first = first;
        this.last = last;
    }

    public override string ToString()
    {
        return this.fullname;
    }
}

Далее я попробую подход POCO и опубликую результаты. Большое вам спасибо!

EDIT Вот что выглядит как мясо исключения. Я не думаю, что остальные исключения будут полезны:

Crashed Thread:        0  tid_307  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_CRASH (SIGABRT)
Exception Codes:       0x0000000000000000, 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

External Modification Warnings:
Debugger attached to process.

Application Specific Information:
abort() called
WealthBox Addon(6016,0x11d9ae5c0) malloc: *** error for object 0x7fff7f110880: pointer being freed was not allocated


Thread 0 Crashed:: tid_307  Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib          0x00007fff7f08223e __pthread_kill + 10
1   libsystem_pthread.dylib         0x00007fff7f138c1c pthread_kill + 285
2   libsystem_c.dylib               0x00007fff7efeb268 __abort + 144
3   libsystem_c.dylib               0x00007fff7efeb1d8 abort + 142
4   libsystem_malloc.dylib          0x00007fff7f0fa6e2 malloc_vreport + 545
5   libsystem_malloc.dylib          0x00007fff7f0fa4a3 malloc_report + 152
6   libsystem_malloc.dylib          0x00007fff7f0f2aff malloc_set_zone_name + 47
7   ???                             0x00000001162ad420 0 + 4666872864
8   ???                             0x000000011616c6a3 0 + 4665558691
9   ???                             0x0000000116275739 0 + 4666644281
10  ???                             0x0000000116265443 0 + 4666577987
11  ???                             0x000000011625cbd3 0 + 4666543059
12  ???                             0x000000011618480b 0 + 4665657355
13  ???                             0x00000001162755bb 0 + 4666643899
14  ???                             0x0000000116265443 0 + 4666577987
15  ???                             0x000000011625cbd3 0 + 4666543059
16  ???                             0x000000011618480b 0 + 4665657355
17  ???                             0x000000011618885b 0 + 4665673819
18  ???                             0x0000000116185c7b 0 + 4665662587
19  ???                             0x000000011618486b 0 + 4665657451
20  ???                             0x000000011609f303 0 + 4664718083
21  ???                             0x000000011609cc03 0 + 4664708099
22  ???                             0x000000011609c84e 0 + 4664707150
23  ???                             0x0000000116095663 0 + 4664677987
24  ???                             0x0000000116087a33 0 + 4664621619
25  Browning-Financial.WealthBox-Addon  0x000000010edc5593 mono_jit_runtime_invoke + 1443 (mini-runtime.c:2806)
26  Browning-Financial.WealthBox-Addon  0x000000010eeaee4f mono_runtime_invoke_checked + 127 (object.c:2887)
27  Browning-Financial.WealthBox-Addon  0x000000010eeb36fc mono_runtime_invoke + 76 (object.c:2941)
28  Browning-Financial.WealthBox-Addon  0x000000010ecadaa2 xamarin_invoke_trampoline + 6018 (trampolines-invoke.m:456)
29  Browning-Financial.WealthBox-Addon  0x000000010ecaec7d xamarin_arch_trampoline + 189 (trampolines-x86_64.m:547)
30  Browning-Financial.WealthBox-Addon  0x000000010ecb00b1 xamarin_x86_64_common_trampoline + 110
31  com.apple.AppKit                0x00007fff4f3deb5a -[NSViewController _sendViewDidLoad] + 97
32  com.apple.AppKit                0x00007fff4f3dbeb5 _noteLoadCompletionForObject + 645
33  com.apple.AppKit                0x00007fff4f24d99f -[NSIBObjectData nibInstantiateWithOwner:options:topLevelObjects:] + 2086
34  com.apple.AppKit                0x00007fff4f3e3114 -[NSNib _instantiateNibWithExternalNameTable:options:] + 679
35  com.apple.AppKit                0x00007fff4f3e2d70 -[NSNib _instantiateWithOwner:options:topLevelObjects:] + 136
36  com.apple.AppKit                0x00007fff4f3e1fdc -[NSViewController loadView] + 343
37  com.apple.AppKit                0x00007fff4f3ddb60 -[NSViewController _loadViewIfRequired] + 75
38  com.apple.AppKit                0x00007fff4f3ddacb -[NSViewController view] + 30
39  com.apple.AppKit                0x00007fff4f4d01da -[NSWindow _contentViewControllerChanged] + 109
40  com.apple.Foundation            0x00007fff540c7450 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 331
41  com.apple.AppKit                0x00007fff4f3da987 -[NSWindow setValue:forKey:] + 111
42  com.apple.AppKit                0x00007fff4f32ce0c -[NSIBUserDefinedRuntimeAttributesConnector establishConnection] + 637
43  com.apple.AppKit                0x00007fff4f24d739 -[NSIBObjectData nibInstantiateWithOwner:options:topLevelObjects:] + 1472
44  com.apple.AppKit                0x00007fff4f3e3114 -[NSNib _instantiateNibWithExternalNameTable:options:] + 679
45  com.apple.AppKit                0x00007fff4f3e2d70 -[NSNib _instantiateWithOwner:options:topLevelObjects:] + 136
46  com.apple.AppKit                0x00007fff4fada64c -[NSStoryboard instantiateControllerWithIdentifier:] + 236
47  com.apple.AppKit                0x00007fff4f23e855 NSApplicationMain + 702
48  ???                             0x00000001151c56b7 0 + 4649146039
49  ???                             0x00000001151c53ab 0 + 4649145259
50  Browning-Financial.WealthBox-Addon  0x000000010edc5593 mono_jit_runtime_invoke + 1443 (mini-runtime.c:2806)
51  Browning-Financial.WealthBox-Addon  0x000000010eeaee4f mono_runtime_invoke_checked + 127 (object.c:2887)
52  Browning-Financial.WealthBox-Addon  0x000000010eeb5c2e mono_runtime_exec_main_checked + 110 (object.c:4782)
53  Browning-Financial.WealthBox-Addon  0x000000010ed1087f mono_jit_exec + 287 (driver.g.c:1210)
54  Browning-Financial.WealthBox-Addon  0x000000010ed1384a mono_main + 11114 (driver.g.c:2418)
55  Browning-Financial.WealthBox-Addon  0x000000010ecb0a8e xamarin_main + 1182 (launcher.m:661)
56  Browning-Financial.WealthBox-Addon  0x000000010ecb1a04 main + 36 (launcher.m:679)
57  libdyld.dylib                   0x00007fff7ef42ed9 start + 1

Thread 1:
0   libsystem_pthread.dylib         0x00007fff7f1353f8 start_wqthread + 0
1   ???                             0x0000000054485244 0 + 1414025796

Thread 2:: SGen worker
0   libsystem_kernel.dylib          0x00007fff7f07f7de __psynch_cvwait + 10
1   libsystem_pthread.dylib         0x00007fff7f139593 _pthread_cond_wait + 724
2   Browning-Financial.WealthBox-Addon  0x000000010ef7416e thread_func + 558 (mono-os-mutex.h:173)
3   libsystem_pthread.dylib         0x00007fff7f136305 _pthread_body + 126
4   libsystem_pthread.dylib         0x00007fff7f13926f _pthread_start + 70
5   libsystem_pthread.dylib         0x00007fff7f135415 thread_start + 13

Thread 3:: Finalizer
0   libsystem_kernel.dylib          0x00007fff7f07c1b6 semaphore_wait_trap + 10
1   Browning-Financial.WealthBox-Addon  0x000000010ee4c7a5 finalizer_thread + 293 (mono-os-semaphore.h:90)
2   Browning-Financial.WealthBox-Addon  0x000000010ef01b50 start_wrapper + 704 (threads.c:1004)
3   libsystem_pthread.dylib         0x00007fff7f136305 _pthread_body + 126
4   libsystem_pthread.dylib         0x00007fff7f13926f _pthread_start + 70
5   libsystem_pthread.dylib         0x00007fff7f135415 thread_start + 13

Thread 4:: Debugger agent
0   libsystem_kernel.dylib          0x00007fff7f07f3e6 __recvfrom + 10
1   Browning-Financial.WealthBox-Addon  0x000000010ed0515e socket_transport_recv + 78 (debugger-agent.c:1153)
2   Browning-Financial.WealthBox-Addon  0x000000010ecf5a7c debugger_thread + 28588 (debugger-agent.c:1558)
3   Browning-Financial.WealthBox-Addon  0x000000010ef01b50 start_wrapper + 704 (threads.c:1004)
4   libsystem_pthread.dylib         0x00007fff7f136305 _pthread_body + 126
5   libsystem_pthread.dylib         0x00007fff7f13926f _pthread_start + 70
6   libsystem_pthread.dylib         0x00007fff7f135415 thread_start + 13

Thread 5:
0   libsystem_pthread.dylib         0x00007fff7f1353f8 start_wqthread + 0
1   ???                             0x0000000054485244 0 + 1414025796

Thread 0 crashed with X86 Thread State (64-bit):
  rax: 0x0000000000000000  rbx: 0x000000011d9ae5c0  rcx: 0x00007ffee0f81a18  rdx: 0x0000000000000000
  rdi: 0x0000000000000307  rsi: 0x0000000000000006  rbp: 0x00007ffee0f81a50  rsp: 0x00007ffee0f81a18
   r8: 0x0000000000000000   r9: 0x0000000000989680  r10: 0x0000000000000000  r11: 0x0000000000000206
  r12: 0x0000000000000307  r13: 0x000000011597b000  r14: 0x0000000000000006  r15: 0x000000000000002d
  rip: 0x00007fff7f08223e  rfl: 0x0000000000000206  cr2: 0x00007fffb1d2c188

Logical CPU:     0
Error Code:      0x02000148
Trap Number:     133

Ответы [ 2 ]

0 голосов
/ 10 января 2019

ОК, спасибо Эвенги Назарову, который указал мне верное направление, у меня есть рабочее решение.

Во-первых, вот POCO-версия моего упрощенного класса:

public class ContactDto
{
    private string _fullname = String.Empty;

    public int id { get; set; }

    public string first { get; set; }

    public string last { get; set; }

    [JsonIgnore]
    public string fullname {
        get { return this.first + " " + this.last; }
        set { _fullname = value; }
    }
}

Обратите внимание, что NSObject наследования или украшения имущества (кроме [JsonIgnore].

Изменен ContactRoot на это:

public class ContactRoot
{
    [JsonIgnore] // Do not serialize this
    public List<SimpleContact> SimpleContacts { get; set; }

    [JsonProperty(PropertyName = nameof(Contacts))]
    public List<ContactDto> SerializableContacts { get; set; }
}

Затем я создал методы преобразования для преобразования версий DTO и NSObject, используя System.Reflection:

public ContactDto ConvertToDto(SimpleContact simpleContact)
    {
        var contactdto = new ContactDto();
        foreach (PropertyInfo prop in simpleContact.GetType().GetProperties().Where(t => t.DeclaringType == typeof(SimpleContact)))
        {
            var value = prop.GetValue(simpleContact);
            if (value != null)
            {
                var prop2 = contactdto.GetType().GetProperty(prop.Name);
                prop2.SetValue(contactdto, value);
            }
        }
        return contactdto;
    }
public SimpleContact ConvertToContact(ContactDto contactDto)
    {
        var simplecontact = new SimpleContact();
        foreach (PropertyInfo prop in contactDto.GetType().GetProperties())
        {
            var value = prop.GetValue(contactDto);
            if (value != null)
            {
                var prop2 = simplecontact.GetType().GetProperty(prop.Name);
                prop2.SetValue(simplecontact, value);
            }
        }
        return simplecontact;
    }

Тогда мой новый метод Сериализации:

var contactroot = new ContactRoot
            {
                SimpleContacts = DataSource.SimpleContacts,
                SerializableContacts = new List<ContactDto>()
            };

            foreach (var simplecontact in contactroot.SimpleContacts)
            {
                contactroot.SerializableContacts.Add(ConvertToDto(simplecontact));
            }

            var desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            var filename = Path.Combine(desktop, "WBAddon.json");
            if (File.Exists(filename))
            {
                File.Delete(filename);
            }

            using (StreamWriter file = File.CreateText(filename))
            {
                var serializer = new JsonSerializer()
                {
                    Formatting = Formatting.Indented,
                    TypeNameHandling = TypeNameHandling.Auto,
                    TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple,
                    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                };
                await Task.Run(() => serializer.Serialize(file, contactroot));
            }

И десериализация:

var jsettings = new JsonSerializerSettings
            {
                Formatting = Formatting.Indented,
                TypeNameHandling = TypeNameHandling.Auto,
                TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple,
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore
            };
            string json = string.Empty;
            using (StreamReader file = new StreamReader(filename))
            {
                json = file.ReadToEnd();

            }

            var contactroot = JsonConvert.DeserializeObject<ContactRoot>(json);
            DataSource.SimpleContacts = new List<SimpleContact>();
            foreach (var contactdto in contactroot.SerializableContacts)
            {
                DataSource.SimpleContacts.Add(ConvertToContact(contactdto));
            }

Работает так, как я надеялся! Теперь мне просто нужно создать dto-версию моего полного класса Contact со всеми 70+ свойствами. Возможно, есть и лучший способ, но он выполняет свою работу.

0 голосов
/ 10 января 2019

Всегда лучше придерживаться простого DTO (объекта передачи данных) при сериализации / десериализации данных, которые являются POD (Plain Old Data, т. Е. Содержит только свойства get / set полей, с которыми не связана бизнес-логика).

В этом смысле типом ContactRoot является POD, однако типом контакта не является POD (из-за наследования NSObject). Для этого сценария я бы ввел отдельный тип DTO для контакта, который будет следовать стандарту POD. Вы можете создать альтернативное свойство для списка контактов и поиграть с атрибутами JsonIgnore и JsonProperty, чтобы имитировать желаемое поведение.

Быстрый фрагмент:

public class ContactDto
{
    /* List relevant properties here */
}

public class ContactRoot
{
    [JsonIgnore] // Do not serialize this
    public List<Contact> Contacts { get; set; }

    [JsonProperty(Propertyname = nameof(Contacts)]
    public List<ContactDto> SerializableContacts { 
        get => Contacts?.Select(x => /* data extraction */).ToList();
        set => Contacts = value?.Select(x => /* data extraction */)?.ToList();
    }
}

Дополнение: похоже, что для языков CLR POD называется POCO

...