c# - Как десериализовать универсальный список <T>, когда я не знаю тип (T)?

Вы попробовали gdb-w cygwin gdb. Это - supossed для имения интерфейса окон, который работает довольно хорошо.

единственная проблема, которую я нашел, состоит в том, что на моей существующей машине это не выполняло тот путь, пока я не установил ddd. Я подозреваю, что это требует tcltk, который был установлен, когда я установил ddd.

5
задан AakashM 26 November 2009 в 17:23
поделиться

2 ответа

С BinaryFormatter вам не требуется , чтобы знать тип; метаданные включены в поток (увеличивая его, но эй!). Однако вы не можете преобразовать , если не знаете тип. Часто в этом сценарии вам приходится использовать общеизвестные интерфейсы (неуниверсальные , IList и т.д.) и отражение. И много всего.

Я также не могу придумать огромного требования знать тип, отображаемый в PropertyGrid - поскольку он принимает объект , просто укажите, что BinaryFormatter предоставляет. Есть ли здесь конкретная проблема? Опять же, вы можете захотеть проверить IList (не общий) - но не стоит беспокоиться о IList , поскольку это не t что проверяет PropertyGrid !

Вы, конечно, можете найти T , если вы хотите ( так ) - и использовать MakeGenericType () и Activator.CreateInstance - некрасиво.


ОК; вот способ использования настраиваемых дескрипторов, который не требует знания чего-либо об объекте или типе списка; если вы действительно хотите, то можно развернуть элементы списка непосредственно в свойствах, поэтому в этом примере вы увидите 2 фальшивых свойства («Fred» и «Wilma») - это дополнительная работа, хотя ; -p

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

class Person
{
    public string Name { get; set; }
    public DateTime DateOfBirth { get; set; }

    public override string ToString() {
        return Name;
    }
}

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Person fred = new Person();
        fred.Name = "Fred";
        fred.DateOfBirth = DateTime.Today.AddYears(-23);
        Person wilma = new Person();
        wilma.Name = "Wilma";
        wilma.DateOfBirth = DateTime.Today.AddYears(-20);

        ShowUnknownObject(fred, "Single object");
        List<Person> list = new List<Person>();
        list.Add(fred);
        list.Add(wilma);
        ShowUnknownObject(list, "List");
    }
    static void ShowUnknownObject(object obj, string caption)
    {
        using(Form form = new Form())
        using (PropertyGrid grid = new PropertyGrid())
        {
            form.Text = caption;
            grid.Dock = DockStyle.Fill;
            form.Controls.Add(grid);
            grid.SelectedObject = ListWrapper.Wrap(obj);
            Application.Run(form);
        }
    }
}

[TypeConverter(typeof(ListWrapperConverter))]
public class ListWrapper
{
    public static object Wrap(object obj)
    {
        IListSource ls = obj as IListSource;
        if (ls != null) obj = ls.GetList(); // list expansions

        IList list = obj as IList;
        return list == null ? obj : new ListWrapper(list);
    }
    private readonly IList list;
    private ListWrapper(IList list)
    {
        if (list == null) throw new ArgumentNullException("list");
        this.list = list;
    }
    internal class ListWrapperConverter : TypeConverter
    {
        public override bool GetPropertiesSupported(ITypeDescriptorContext context)
        {
            return true;
        }
        public override PropertyDescriptorCollection GetProperties(
            ITypeDescriptorContext context, object value, Attribute[] attributes) {
            return new PropertyDescriptorCollection(
                new PropertyDescriptor[] { new ListWrapperDescriptor(value as ListWrapper) });
        }
    }
    internal class ListWrapperDescriptor : PropertyDescriptor {
        private readonly ListWrapper wrapper;
        internal ListWrapperDescriptor(ListWrapper wrapper) : base("Wrapper", null)
        {
            if (wrapper == null) throw new ArgumentNullException("wrapper");
            this.wrapper = wrapper;
        }
        public override bool ShouldSerializeValue(object component) { return false; }
        public override void ResetValue(object component) {
            throw new NotSupportedException();
        }
        public override bool CanResetValue(object component) { return false; }
        public override bool IsReadOnly {get {return true;}}
        public override void SetValue(object component, object value) {
            throw new NotSupportedException();
        }
        public override object GetValue(object component) {
            return ((ListWrapper)component).list;
        }
        public override Type ComponentType {
            get { return typeof(ListWrapper); }
        }
        public override Type PropertyType {
            get { return wrapper.list.GetType(); }
        }
        public override string DisplayName {
            get {
                IList list = wrapper.list;
                if (list.Count == 0) return "Empty list";

                return "List of " + list.Count
                    + " " + list[0].GetType().Name;
            }
        }
    }
}
3
ответ дан 14 December 2019 в 19:16
поделиться

Если сериализатор, который вы используете, не сохраняет тип - по крайней мере, вы должны сохранить тип T вместе с данными и используйте их для создания общего списка рефлексивно:

//during storage:
Type elementType = myList.GetType().GetGenericTypeDefinition().GetGenericArguments[0];
string typeNameToSave = elementType.FullName;

//during retrieval
string typeNameFromDatabase = GetTypeNameFromDB();
Type elementType = Type.GetType(typeNameFromDatabase);
Type listType = typeof(List<>).MakeGenericType(new Type[] { elementType });

Теперь у вас есть listType , который является точным List , который вы использовали (скажем, Список ). Вы можете передать этот тип в процедуру десериализации.

2
ответ дан 14 December 2019 в 19:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: