Le bloc-notes se comporte différemment in.NET 3.5 et 4, mais pourquoi?

nous avons récemment mis à niveau un très grand projet de .net framework 3.5 à 4, et au début tout semblait fonctionner de la même façon. Mais maintenant les bogues ont commencé à apparaître sur les opérations de copier-coller. J'ai réussi à faire une petite application reproductible, qui montre les différents comportements dans .NET 3.5 et 4. J'ai aussi trouvé une solution de rechange (sérialiser manuellement les données au presse-papiers), mais il me reste un besoin de savoir "pourquoi" il y a une différence de comportement.

C'est la petite application de test je fait:

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;

namespace ClipboardTest
{
    public class Program
    {
        [Serializable]
        public class Element
        {
            public Element(string name)
            {
                this.name = name;
            }

            public string name;
        }

        public static List<Element> TestSerializer(List<Element> obj)
        {
            var memoryStream = new MemoryStream();
            var formatter = new BinaryFormatter();
            formatter.Serialize(memoryStream, obj);
            return (List<Element>)formatter.Deserialize(new MemoryStream(memoryStream.GetBuffer()));
        }

        public static List<Element> TestClipboard(List<Element> obj)
        {
            Clipboard.SetDataObject(obj);
            return (List<Element>)Clipboard.GetDataObject().GetData(typeof(List<Element>));
        }

        public static void DumpObject(string testName, List<Element> obj)
        {
            if (obj == null)
            {
                Console.WriteLine("{0} : List is null", testName);
                return;
            }
            foreach (var prop in obj)
            {
                Console.WriteLine("{0} : {1}", testName, prop.name);
            }
        }

        [STAThread]
        static void Main()
        {
            var copyData = new List<Element> { new Element("all good") };
            DumpObject("Serializer", TestSerializer(copyData));
            DumpObject("Clipboard", TestClipboard(copyData));
        }
    }
}

.NET 3.5 Sortie:

Sérialiseur : tous les bons

Presse-papiers : tous les bons

.NET 4 sortie:

Sérialiseur : tous les bons

Presse-papiers : la Liste est null

j'ai regardé la source .NET pour la classe Presse-papiers & DataObject, mais je ne pouvais pas voir quel serialiseur était utilisé. La documentation MSDN dit que le type doit être sérialisable, ce qui dans ce cas à la fois le List<> et les classes D'éléments sont. Copier un élément objet fonctionne très bien, mais dès que je copie une liste d'éléments, il casse.

pour tester, j'ai créé 2 projets C# "Application Console" dans Visual Studio 2010 SP1. Le premier projet que j'ai quitté avec le paramètre par défaut "cadre cible" de ".net Framework 4 Client Profile". Le deuxième projet que j'ai modifié pour utiliser ".net Framework 3.5 Client Profile".

informations supplémentaires sur mes formulaires DLL version:

Nom du fichier Original: System.Windows.Forme.dll

Version de fichier/Prouct version : 4.0.30319.235

Langue: Anglais (États-Unis)

Date de modification: 16-02-2012 22:50

25
demandé sur remio 2012-02-26 15:47:10
la source

1 ответов

j'ai repro. Vous pouvez obtenir plus d'informations sur le bogue avec les Exceptions Debug+, cochez la case Jeté Pour CLR exceptions. Cela arrêtera le programme quand une exception interne est lancée par le code du presse-papiers dans le cadre. Le IDataObject.La méthode d'implémentation de GetDataHere () échoue avec une exception COM, "structure FORMATETC non valide (Exception de HRESULT: 0X80040064 (DV_E_FORMATETC))".

Il y a quelque chose qui ne va pas avec le format. Cela devient clair lorsque vous définissez un point d'arrêt après le presse-papiers.Déclaration de SetDataObject(obj). Et mettre le presse-papiers.GetDataObject ().GetFormats () dans une expression de surveillance de débogueur. Je vois:

"le Système de.Collection.Générique.Liste 1 [[ClipboardTest.Program+Element, ConsoleApplication1, Version=1.0.0.0, Culture=neutral, Public"

notez comment la chaîne est tronquée, la partie de Publiceytoken a été mutilée. Vous pouvez modifier arbitrairement cette chaîne tronquée en changeant le nom de l'espace de noms et le nom du projet. Faites-les assez court et le programme n'échouera pas.

c'est Clairement la cause du problème. La longueur de la corde est clippée à 127 caractères, n'importe quel type dont le nom complet est plus long que cela va causer cet échec. Avec une forte probabilité que ce soit un type générique, car ils ont des noms très longs.

Veuillez signaler ce bogue à connect.microsoft.com. Votre code montre le bug très bien, seulement l'affichage d'un lien dans votre rapport de bogue sera suffisant. Je n'ai pas une très bonne solution, s'assurer que le nom est assez court n'est pas très pratique. Mais vous pouvez le faire avec un code comme ceci:

        // Put it on the clipboard, use a wrapper type with a short name
        var envelope = new List<object>();
        envelope.AddRange(obj);
        Clipboard.SetDataObject(envelope);

        // Retrieve from clipboard, unwrap back to original type
        envelope = (List<object>)Clipboard.GetDataObject().GetData(typeof(List<object>));
        var retval = new List<Element>();
        retval.AddRange(envelope.Cast<Element>());
        return retval;

mise à jour: ce bug est signalé corrigé dans VS2013.

26
répondu Hans Passant 2014-04-30 00:03:35
la source

Autres questions sur