Делегат, вызывающий универсальный метод в процессоре привязок универсального класса во время десериализации - PullRequest
2 голосов
/ 07 ноября 2008

Кто-нибудь еще сталкивался с этой проблемой раньше? У меня есть метод, который вызывает универсальный метод с делегатом внутри универсального класса. Я пометил класс как Serializable, и он сериализуется без жалоб. Но когда я пытаюсь десериализовать объект этого класса, он привязывает процессор и зависает на компьютере.

Пример кода:

public delegate T CombinationFunctionDelegate<T,U,V>(U a, V b);

    [Serializable]
public class SDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    public SDictionary()
        : base()
    {
    }

    protected SDictionary(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {}

    [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
    }

    public List<ListItem> ToListItems()
    {
        return Convert(delegate(TKey key, TValue value)
        {
            return new ListItem(key.ToString(), value.ToString());
        });
    }

    public List<U> Convert<U>(CombinationFunctionDelegate<U, TKey, TValue> converterFunction)
    {
        List<U> res = new List<U>();
        foreach (TKey key in Keys)
            res.Add(converterFunction(key, this[key]));

        return res;
    }
}

Я могу поместить экземпляр этого класса в ViewState (например) очень хорошо, но когда я пытаюсь извлечь объект из ViewState снова, ЦП на машине пикирует, и вызов десериализации никогда не возвращается (т. Е. Бесконечный цикл) .

Когда я удаляю метод ToListItems (), все прекрасно работает. Это действительно странно, или я просто не понимаю сериализации? =)

Ответы [ 5 ]

1 голос
/ 07 ноября 2008

Это код, который у меня сейчас есть, который отлично работает?

    [Serializable]
    public class SDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        public SDictionary()
            : base()
        {
        }

        protected SDictionary(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }

        public List<ListItem> ToListItems()
        {
            return this.Convert(delegate(TKey key, TValue value)
            {
                return new ListItem(key.ToString(), value.ToString());
            });
        }

        public List<U> Convert<U>(CombinationFunctionDelegate<U, TKey, TValue> converterFunction)
        {
            List<U> res = new List<U>();
            foreach (TKey key in Keys)
                res.Add(converterFunction(key, this[key]));

            return res;
        }


    }

    class Program
    {

        static void Main(string[] args)
        {
            SDictionary<string, string> b = new SDictionary<string, string>();
            b.Add("foo", "bar");

            System.IO.MemoryStream memStream = new System.IO.MemoryStream();
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter f = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            f.Serialize(memStream, b);
            memStream.Position = 0;

            b = f.Deserialize(memStream) as SDictionary<string, string>;
        }

    }

Помогает ли это вообще?

Редактировать: снова подправлен.

0 голосов
/ 07 ноября 2008

Вот статья базы знаний об ошибке тоже, если кому-то это нужно: http://support.microsoft.com/?id=957543

0 голосов
/ 07 ноября 2008

Вы используете VS2008 SP1? Есть известная проблема с SP1.
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=361615

0 голосов
/ 07 ноября 2008

Может ли быть так, что анонимный метод имеет ссылку на экземпляр, в котором он находится? Я не могу ответить на это.

Ваш комментарий указывает на то, что это возможно. Вот самый простой выход: не используйте анонимные методы.

public ListItem ToListItem(TKey key, TValue value)
{
  return new ListItem(key.ToString(), value.ToString());
}

Что я могу ответить, так это то, что методы этого класса могут быть запущены в соответствии с открытым контрактом Dictionary , и поэтому нет необходимости в этом классе, когда вы можете писать методы расширения для Dictionary (при условии C # 3)

Примерно так (от руки код может быть не на 100% правильным)

public static List<ListItem> ToListItems(this Dictionary<T, U> source)
{
  return source
    .Select(x => new ListItem(x.key.ToString(), x.value.ToString()))
    .ToList();
}

public static List<V> Convert<V>
(
  this Dictionary<T, U> source,
  Func<T, U, V> converterFunction
)
{
  return source
    .Select(x => converterFunction(x.Key, x.Value))
    .ToList();
}
0 голосов
/ 07 ноября 2008

Прежде всего, Dictionary <> уже реализует ISerializable, поэтому вам не нужно указывать эту простоту!

Во-вторых, вы переопределяете GetObjectData (), но, похоже, вы не вызываете Dictionary.GetObjectData (), поэтому словарь может не десериализоваться? Следовательно, когда вы получаете доступ к этим ключам, вы сталкиваетесь с «проблемой».

Да, я думаю здесь вслух;)

Возможно, вы могли бы попробовать это:

public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
  // deserialize the dictionary first
  base.GetObjectData(info, context);

  // the rest of your code
  // ...
}

Я не пробовал и не компилировал это, но это может быть что-то, чтобы рассмотреть?

Удачи:)

...