Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

306
Visualizações
El visualizador de depuración que apunta a DateTime no transfiere el valor

He escrito un visualizador de depuración de Visual Studio que apunta a DateTime ( repo ). Mi problema es que el lado del depurador solo pasa el valor de destino al lado depurado si la expresión de destino es de object , no de DateTime ( problema ).

He publicado un repositorio de GH que contiene un MCVE que reproduce el problema . El lado del depurador se ve así:

 protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider) { var response = objectProvider.TransferObject(5); var msg = response switch { string s => s, IEnumerable e => string.Join(", ", e.Cast<object>()), _ => "Unhandled type" }; MessageBox.Show(msg); }

y el lado depurado se ve así:

 public override void TransferData(object target, Stream incomingData, Stream outgoingData) { int? repetitions = Deserialize(incomingData) switch { int i when i > 0 => i, string s when int.TryParse(s, out int i) && i > 0 => i, _ => null }; object toSerialize = repetitions is null ? $"Invalid value for repetitions" : target switch { DateTime dt => Repeat(dt, repetitions.Value).ToArray(), null => $"{nameof(target)} is null", _ => $"Not implemented for target of type {target.GetType().FullName}" as object }; Serialize(outgoingData, toSerialize); }

Después de compilar e instalar el visualizador, y comenzar a depurar el siguiente código:

 var dte = DateTime.UtcNow; object o = dte;

si paso el cursor sobre o y activo el visualizador, el DateTime de destino se pasa al lado depurado y devuelve una matriz de DateTime . Pero si activo el visualizador en dte , obtengo que el target is null , lo que implica que el lado de depuración ha recibido null en el parámetro de target .

¿Qué podría estar causando esto? ¿Cómo podría solucionarlo?


Algunas notas aleatorias

  • No es porque el lado del depurador sea siempre de 32 bits y el lado del depurador sea a veces de 64 bits.
  • Tampoco se debe a los diferentes TFM: cuando el lado del depurador apunta a .NET Framework, mientras que el lado depurado puede apuntar a .NET Standard o .NET Core.
  • Solo se ve afectada la anulación de TransferData ; la anulación de GetData siempre obtiene el valor objetivo (en realidad estoy usando GetData para solucionar esto, pero realmente prefiero usar GetData para otra cosa). Intenté probar ReplaceData / ReplaceObject , pero la propiedad IsObjectReplaceable siempre devuelve false .
  • Probé con otros tipos de valores ( TimeSpan , DateTimeOffset y una struct personalizada) y observé el mismo comportamiento. Sin embargo, cuando probé contra int , el proceso de destino falla y la sesión de depuración se interrumpe.
  • ¿Apuntando contra un DateTime? muestra el mismo comportamiento que DateTime ; Me imagino que esto se debe a que ambos están serializados de la misma manera.

Seguimiento de la pila del golpe de excepción cuando se dirige de manera similar a un int

En respuesta a este comentario , el mensaje de error al visualizar un int es el siguiente:

El proceso de destino finalizó con el código -1073740791 (0xC0000409) mientras evaluaba la función 'Microsoft.VisualStudio.DebuggerVisualizers.DebugeeSide.Impl.ClrCustomVisualizerDebuggeeHost.TransferData'.

Si el problema ocurre regularmente, considere deshabilitar la configuración de Herramientas->Opciones "Depuración->General->Habilitar evaluación de propiedades y otras llamadas a funciones implícitas" o depurar la causa evaluando la expresión desde la ventana Inmediato. Consulte la ayuda para obtener información sobre cómo hacer esto.

seguido de otro mensaje:

No se pudo cargar el visor personalizado.

sobre el cual el proceso de destino se bloquea y finaliza la sesión de depuración.

Intenté sin éxito adjuntar un depurador usando un punto de interrupción de código ( Debugger.Break() ). Si devuelvo la pila de llamadas del visualizador ( new System.Diagnostics.StackTrace().ToString() ) y el visualizador se ejecuta correctamente, obtengo lo siguiente:

en SimpleValueTypeVisualizer.Debuggee.VisualizerObjectSource.TransferData(Objeto objetivo, Stream incomingData, Stream outgoingData)

en Microsoft.VisualStudio.DebuggerVisualizers.DebuggeeSide.Impl.ClrCustomVisualizerDebuggeeHost.TransferData(Object visualizatedObject, Byte[] uiSideData)

en TestNoRef.Program.Main(String[] argumentos)

lo que parecería implicar alguna excepción en Microsoft.VisualStudio.DebuggerVisualizers.DebuggeeSide.Impl.ClrCustomVisualizerDebuggeeHost.TransferData .

Cuando abrí DebuggerVisualizers.dll usando ILSpy, el método TransferData relevante se ve así:

 // Microsoft.VisualStudio.DebuggerVisualizers.DebuggeeSide.Impl.ClrCustomVisualizerDebuggeeHost using System.IO; public byte[] TransferData(object visualizedObject, byte[] uiSideData) { MemoryStream memoryStream = new MemoryStream(); MemoryStream incomingData = ((uiSideData != null) ? new MemoryStream(uiSideData) : null); m_debuggeeSideVisualizerObject.TransferData(visualizedObject, incomingData, memoryStream); return memoryStream.ToArray(); }

Supongo que la excepción está en la tercera línea del método ( MemoryStream incomingData = ... ). Pero todavía no tengo claro los detalles de la excepción, particularmente por qué el problema solo surge con un valor sin caja y no con un valor con caja.


Detalles del registro de eventos

Según este comentario , incluyo datos del registro de eventos creado al abrir el visualizador en una expresión de tipo int :

 Log Name: Application Source: Application Error Date: 22/04/2021 12:14:36 Event ID: 1000 Task Category: (100) Level: Error Keywords: Classic User: N/A Computer: LAPTOP-7O43T4OO Description: Faulting application name: TestNoRef.exe, version: 1.0.0.0, time stamp: 0xd9f9e12d Faulting module name: clr.dll, version: 4.8.4341.0, time stamp: 0x6023024f Exception code: 0xc0000409 Fault offset: 0x00574845 Faulting process ID: 0x94c4 Faulting application start time: 0x01d73757c33e87c0 Faulting application path: *********** Faulting module path: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll Report ID: 1dcf070b-71ff-4279-be71-822698cc6168 Faulting package full name: Faulting package-relative application ID: Event Xml: <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event"> <System> <Provider Name="Application Error" /> <EventID Qualifiers="0">1000</EventID> <Version>0</Version> <Level>2</Level> <Task>100</Task> <Opcode>0</Opcode> <Keywords>0x80000000000000</Keywords> <TimeCreated SystemTime="2021-04-22T09:14:36.4507272Z" /> <EventRecordID>1180760705</EventRecordID> <Correlation /> <Execution ProcessID="0" ThreadID="0" /> <Channel>Application</Channel> <Computer>LAPTOP-7O43T4OO</Computer> <Security /> </System> <EventData> <Data>TestNoRef.exe</Data> <Data>1.0.0.0</Data> <Data>d9f9e12d</Data> <Data>clr.dll</Data> <Data>4.8.4341.0</Data> <Data>6023024f</Data> <Data>c0000409</Data> <Data>00574845</Data> <Data>94c4</Data> <Data>01d73757c33e87c0</Data> <Data>***********</Data> <Data>C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll</Data> <Data>1dcf070b-71ff-4279-be71-822698cc6168</Data> <Data> </Data> <Data> </Data> </EventData> </Event>
over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

No puedo encontrar una solución adecuada. Podría ser solo un error introducido en una de las últimas versiones y nadie ha encontrado este problema con los tipos de valor hasta ahora. En realidad, lo intenté

 DateTime dte = DateTime.UtcNow; ValueType vt = dte;

Y nuevamente funciona con vt pero no con dte . Agregué un objetivo explícito a net48 por si acaso, pero no cambió nada.

Lo mejor que pude encontrar es una solución muy similar a la que supongo que Zev Spitz está usando, pero tratando de no desperdiciar la anulación de GetData solo para obtener el valor objetivo. No es una solución muy agradable, me temo.

Siempre que desee usar GetData para recuperar un valor diferente, pero se usará en su DialogDebuggerVisualizer.Show override, puede almacenar su valor dentro del objeto VisualizerObjectSource cuando llame a GetData y recuperarlo cuando llame a TransferData, sin transferirlo realmente del depurador al depurador.

 public class VisualizerObjectSource : Microsoft.VisualStudio.DebuggerVisualizers.VisualizerObjectSource { /*static*/ DateTime? _lastDatetime=null; public override void TransferData(object target, Stream incomingData, Stream outgoingData) { target = _lastDatetime; //Calculate here the output value object toSerialize = " is null = " + (target==null).ToString(); Serialize(outgoingData, toSerialize); } public override void GetData(object target, Stream outgoingData) { _lastDatetime = (DateTime)target; //Calculate here what you want to be returned by GetData base.GetData(" The stuff you want to return ", outgoingData); } }

y en su lado del Depurador, asegúrese de llamar a GetObject/GetData antes de llamar a TransferObject()

 protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider) { object MyCustomStuff =objectProvider.GetObject(); var response = objectProvider.TransferObject(5); //[...] string msg = response .ToString(); MessageBox.Show(msg); }
over 4 years ago · Santiago Trujillo Relatório

0

Como mencioné en los comentarios, en realidad no se requiere TransferData . Además, se puede evitar toda la serialización BinaryFormatter (desafortunadamente, solo cuando se transfieren los datos al visualizador del depurador y no cuando se reemplaza un valor editado, pero hay otro truco para eso).

En primer lugar, considere la siguiente configuración:

 [assembly: DebuggerVisualizer(typeof(DateTimeVisualizer), typeof(DateTimeSerializer), Target = typeof(DateTime), Description = "DateTime Debugger Visualizer")]

Donde el serializador es el siguiente:

 // Note that TransferData is not overridden, and we do not call base.GetData so we can // avoid using BinaryFormatter (which often has issues when debugging a .NET Core or newer project) internal class DateTimeSerializer : VisualizerObjectSource { public override void GetData(object target, Stream outgoingData) { var dateTime = (DateTime)target; // Note: do not dispose the writer so the outgoingData remains open. // If targeting newer frameworks you can use the leaveOpen parameter, too. var writer = new BinaryWriter(outgoingData); // What a tiny payload compared to the default BinaryFormatter result... writer.Write(dateTime.Ticks); writer.Write((int)dateTime.Kind); } }

Y en el visualizador mismo, es importante no llamar a GetObject , que intentaría deserializar su flujo mediante BinaryFormatter . En su lugar, use GetData , que devuelve la secuencia sin procesar:

 internal class DateTimeDebuggerVisualizer : DialogDebuggerVisualizer { protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider) { // GetObject would fail here as we have a custom written stream var reader = new BinaryReader(objectProvider.GetData()); var dateTime = new DateTime(reader.ReadInt64(), (DateTimeKind)reader.ReadInt32()); // Show the debugger [...] }

Si su depurador puede editar los datos, entonces reemplazar el valor es otro problema. Desafortunadamente, la serialización de BinaryFormatter no se puede evitar en ese caso. Puede ser un problema si su objeto no es serializable en todos los objetivos (por ejemplo, en .NET Core y superior).

Por supuesto, esto no es un problema en el caso de DateTime , así que solo como una nota al margen: en tal caso, el truco puede ser colocar datos serializables personalizados en ReplaceObject que implementa IObjectReference para que pueda devolver el resultado personalizado en IObjectReference.GetRealObject . Aquí hay uno de esos ejemplos de mis serializadores.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda