¿Cuál es el peor gotcha en C# or.NET? [cerrado]


Recientemente estuve trabajando con un objeto DateTime, y escribí algo como esto:

DateTime dt = DateTime.Now;
dt.AddDays(1);
return dt; // still today's date! WTF?

La documentación de intellisense para AddDays() dice que agrega un día a la fecha, lo cual no lo hace - en realidad devuelve una fecha con un día agregado, así que tienes que escribirla como:

DateTime dt = DateTime.Now;
dt = dt.AddDays(1);
return dt; // tomorrow's date

Este me ha mordido varias veces antes, así que pensé que sería útil catalogar las peores gotchas de C#.

 369
Author: MusiGenesis, 2008-10-27

30 answers

private int myVar;
public int MyVar
{
    get { return MyVar; }
}

Blammo. Tu aplicación se bloquea sin seguimiento de pila. Pasa todo el tiempo.

(Observe mayúscula MyVar en lugar de minúscula myVar en el getter.)

 295
Author: Eric Z Beard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-13 07:37:08

Tipo.GetType

El que he visto morder a mucha gente es Type.GetType(string). Se preguntan por qué funciona para tipos en su propio ensamblaje, y algunos tipos como System.String, pero no System.Windows.Forms.Form. La respuesta es que solo se ve en la asamblea actual y en mscorlib.


Métodos anónimos

C # 2.0 introdujo métodos anónimos, llevando a situaciones desagradables como esta:

using System;
using System.Threading;

class Test
{
    static void Main()
    {
        for (int i=0; i < 10; i++)
        {
            ThreadStart ts = delegate { Console.WriteLine(i); };
            new Thread(ts).Start();
        }
    }
}

¿Qué imprimirá eso? Bueno, depende completamente de la agenda. Imprimirá 10 números, pero probablemente no imprimirá 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 que es lo que podrías esperar. El problema es que es la variable i la que ha sido capturada, no su valor en el momento de la creación del delegado. Esto se puede resolver fácilmente con una variable local adicional del ámbito correcto:

using System;
using System.Threading;

class Test
{
    static void Main()
    {
        for (int i=0; i < 10; i++)
        {
            int copy = i;
            ThreadStart ts = delegate { Console.WriteLine(copy); };
            new Thread(ts).Start();
        }
    }
}

Ejecución diferida de bloques iteradores

Esta "prueba unitaria del pobre" no pasa - por qué no?

using System;
using System.Collections.Generic;
using System.Diagnostics;

class Test
{
    static IEnumerable<char> CapitalLetters(string input)
    {
        if (input == null)
        {
            throw new ArgumentNullException(input);
        }
        foreach (char c in input)
        {
            yield return char.ToUpper(c);
        }
    }

    static void Main()
    {
        // Test that null input is handled correctly
        try
        {
            CapitalLetters(null);
            Console.WriteLine("An exception should have been thrown!");
        }
        catch (ArgumentNullException)
        {
            // Expected
        }
    }
}

La respuesta es que el código dentro de la fuente del código CapitalLetters no se ejecuta hasta que se llama primero al método MoveNext() del iterador.

Tengo algunas otras rarezas en mi página de rompecabezas.

 248
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-27 19:47:12

Re-lanzando excepciones

Un gotcha que recibe muchos desarrolladores nuevos, es la semántica de la excepción re-throw.

Muchas veces veo código como el siguiente

catch(Exception e) 
{
   // Do stuff 
   throw e; 
}

El problema es que borra el seguimiento de la pila y hace que el diagnóstico de problemas sea mucho más difícil, ya que no puede rastrear dónde se originó la excepción.

El código correcto es la sentencia throw sin args:

catch(Exception)
{
    throw;
}

O envolver la excepción en otra, y usar la excepción interna para obtener el seguimiento de pila original:

catch(Exception e) 
{
   // Do stuff 
   throw new MySpecialException(e); 
}
 191
Author: Sam Saffron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-23 01:20:16

La Ventana del Reloj Heisenberg

Esto puede morderte mal si estás haciendo cosas de carga bajo demanda, como esta:

private MyClass _myObj;
public MyClass MyObj {
  get {
    if (_myObj == null)
      _myObj = CreateMyObj(); // some other code to create my object
    return _myObj;
  }
}

Ahora digamos que tienes algún código en otro lugar usando esto:

// blah
// blah
MyObj.DoStuff(); // Line 3
// blah

Ahora desea depurar su método CreateMyObj(). Así que pones un punto de interrupción en la línea 3 anterior, con la intención de entrar en el código. Solo para una buena medida, también pones un punto de interrupción en la línea de arriba que dice _myObj = CreateMyObj();, e incluso un punto de interrupción dentro de CreateMyObj().

El el código alcanza tu punto de interrupción en la línea 3. Entras en el código. Espera introducir el código condicional, porque _myObj es obviamente null, ¿verdad? Uh... tan... ¿por qué omitió la condición e ir directamente a return _myObj?! Pasa el ratón sobre _myObj... y, de hecho, tiene un valor! ¿Cómo pasó eso?!

La respuesta es que su IDE hizo que obtuviera un valor, porque tiene una ventana" watch "abierta, especialmente la ventana" Autos", que muestra los valores de todos variables / propiedades relevantes para la línea de ejecución actual o anterior. Cuando alcanzas tu punto de interrupción en la Línea 3, la ventana del reloj decidió que te interesaría saber el valor de MyObj - así que detrás de escena, ignorando cualquiera de tus puntos de interrupción , fue y calculó el valor de MyObj para ti - incluyendo la llamada a CreateMyObj() que establece el valor de _myObj!

Es por eso que llamo a esto la Ventana de Reloj Heisenberg - no se puede observar el valor sin afectándolo... :)

¡TE TENGO!


Edit - Creo que el comentario de @ChristianHayter merece ser incluido en la respuesta principal, porque parece una solución efectiva para este problema. Así que en cualquier momento tienes una propiedad perezosa...

Decora tu propiedad con [DebuggerBrowsable(DebuggerBrowsableState.Nunca)] o [DebuggerDisplay("")]. - Christian Hayter

 187
Author: Shaul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-10 06:40:27

Aquí hay otra vez que me atrae:

static void PrintHowLong(DateTime a, DateTime b)
{
    TimeSpan span = a - b;
    Console.WriteLine(span.Seconds);        // WRONG!
    Console.WriteLine(span.TotalSeconds);   // RIGHT!
}

TimeSpan.Seconds es la porción de segundos del intervalo de tiempo (2 minutos y 0 segundos tienen un valor de segundos de 0).

TimeSpan.TotalSeconds es el intervalo de tiempo completo medido en segundos (2 minutos tiene un valor total de segundos de 120).

 141
Author: Jon B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-12 02:23:27

Fuga de memoria porque no desenganchó eventos.

Esto incluso atrapó a algunos desarrolladores sénior que conozco.

Imagine un formulario WPF con muchas cosas en él, y en algún lugar de allí se suscribe a un evento. Si no cancela la suscripción, el formulario completo se guarda en la memoria después de ser cerrado y des-referenciado.

Creo que el problema que vi fue crear un DispatchTimer en el formulario WPF y suscribirse al evento Tick, si no hace un - = en el temporizador de su formulario ¡pierde memoria!

En este ejemplo, su código de desmontaje debe tener

timer.Tick -= TimerTickEventHandler;

Esto es especialmente complicado ya que creó la instancia del DispatchTimer dentro del formulario WPF, por lo que pensaría que sería una referencia interna manejada por el proceso de Recolección de Basura... desafortunadamente, el DispatchTimer usa una lista interna estática de suscripciones y solicitudes de servicios en el subproceso de interfaz de usuario, por lo que la referencia es 'propiedad' de la clase estática.

 77
Author: Timothy Walters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-10 12:27:47

Tal vez no es realmente un gotcha porque el comportamiento está escrito claramente en MSDN, pero me ha roto el cuello una vez porque lo encontré bastante contrario a la intuición:

Image image = System.Drawing.Image.FromFile("nice.pic");

Este tipo deja el archivo "nice.pic" bloqueado hasta que se elimina la imagen. En el momento en que lo enfrenté, pensé que sería bueno cargar iconos sobre la marcha y no me di cuenta (al principio) de que terminé con docenas de archivos abiertos y bloqueados. Image realiza un seguimiento de dónde había cargado el archivo...

Cómo resolver esto? Pensé que un un trazador de líneas haría el trabajo. Esperaba un parámetro extra para FromFile(), pero no tenía ninguno, así que escribí esto...

using (Stream fs = new FileStream("nice.pic", FileMode.Open, FileAccess.Read))
{
    image = System.Drawing.Image.FromStream(fs);
}
 60
Author: jdehaan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-15 11:53:15

Si cuentas ASP.NET, Yo diría que el ciclo de vida de los formularios web es una gran idea para mí. He pasado incontables horas depurando código webforms mal escrito, solo porque muchos desarrolladores no entienden realmente cuándo usar qué controlador de eventos (yo incluido, tristemente).

 50
Author: Erik van Brakel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-27 22:35:16

Overloaded == operators and untyped containers (arraylists, datasets, etc.):

string my = "my ";
Debug.Assert(my+"string" == "my string"); //true

var a = new ArrayList();
a.Add(my+"string");
a.Add("my string");

// uses ==(object) instead of ==(string)
Debug.Assert(a[1] == "my string"); // true, due to interning magic
Debug.Assert(a[0] == "my string"); // false

Soluciones?

  • Utilice siempre string.Equals(a, b) cuando compare tipos de cadenas

  • Usando genéricos como List<string> para asegurar que ambos operandos sean cadenas.

 47
Author: Jimmy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-16 03:19:15

DateTime.toString ("dd/MM/aaaa") ; Esto realmente no siempre le dará dd/MM/aaaa, sino que tendrá en cuenta la configuración regional y reemplazará su separador de fecha dependiendo de dónde se encuentre. Así que podrías tener dd-MM-aaaa o algo parecido.

La forma correcta de hacer esto es usar DateTime.toString ("dd" / "MM" / "aaaa");


DateTime.toString ("r") se supone que convierte a RFC1123, que utiliza GMT. GMT está dentro de un fracción de segundo de UTC, y sin embargo el especificador de formato "r" no se convierte a UTC, incluso si la fecha y hora en cuestión se especifica como Local.

Esto resulta en la siguiente gotcha (varía dependiendo de la distancia de su hora local desde UTC):

DateTime.Parse("Tue, 06 Sep 2011 16:35:12 GMT").ToString("r")
>              "Tue, 06 Sep 2011 17:35:12 GMT"

Whoops!

 45
Author: romkyns,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-06 17:08:37
[Serializable]
class Hello
{
    readonly object accountsLock = new object();
}

//Do stuff to deserialize Hello with BinaryFormatter
//and now... accountsLock == null ;)

Moraleja de la historia : Los inicializadores de campo no se ejecutan cuando se deserializa un objeto

 43
Author: Nicolas Dorier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-04 11:13:07

Vi este publicado el otro día, y creo que es bastante oscuro y doloroso para aquellos que no saben

int x = 0;
x = x++;
return x;

Como eso devolverá 0 y no 1 como la mayoría esperaría

 42
Author: Mitchel Sellers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-27 19:35:34

Llego un poco tarde a esta fiesta, pero tengo dos trampas que me han mordido recientemente:

Resolución de fecha y hora

La propiedad Ticks mide el tiempo en 10 millonésimas de segundo (bloques de 100 nanosegundos), sin embargo, la resolución no es de 100 nanosegundos, es de aproximadamente 15ms.

Este código:

long now = DateTime.Now.Ticks;
for (int i = 0; i < 10; i++)
{
    System.Threading.Thread.Sleep(1);
    Console.WriteLine(DateTime.Now.Ticks - now);
}

Te dará una salida de (por ejemplo):

0
0
0
0
0
0
0
156254
156254
156254

Del mismo modo, si nos fijamos en DateTime.Ahora.Milisegundo, obtendrá valores en trozos redondeados de 15.625 ms: 15, 31, 46, etc.

Este comportamiento particular varía de un sistema a otro, pero hay otros gotchas relacionados con la resolución en esta API de fecha/hora.


Ruta.Combinar

Una gran manera de combinar rutas de archivo, pero no siempre se comporta de la manera que esperarías.

Si el segundo parámetro comienza con un carácter \, no le dará una ruta completa:

Este código:

string prefix1 = "C:\\MyFolder\\MySubFolder";
string prefix2 = "C:\\MyFolder\\MySubFolder\\";
string suffix1 = "log\\";
string suffix2 = "\\log\\";

Console.WriteLine(Path.Combine(prefix1, suffix1));
Console.WriteLine(Path.Combine(prefix1, suffix2));
Console.WriteLine(Path.Combine(prefix2, suffix1));
Console.WriteLine(Path.Combine(prefix2, suffix2));

Te da esta salida:

C:\MyFolder\MySubFolder\log\
\log\
C:\MyFolder\MySubFolder\log\
\log\
 39
Author: Damovisa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:31

Cuando se inicia un proceso (utilizando System.Diagnósticos) que escribe en la consola, pero nunca lee la consola.Out stream, después de una cierta cantidad de salida de su aplicación aparecerá para colgar.

 37
Author: user25306,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-27 20:58:07

No hay atajos de operador en Linq-To-Sql

Ver aquí .

En resumen, dentro de la cláusula condicional de una consulta Linq-To-Sql, no puede usar atajos condicionales como || y && para evitar excepciones de referencia nula; ¡Linq-To-Sql evalúa ambos lados del operador OR or AND incluso si la primera condición elimina la necesidad de evaluar la segunda condición!

 34
Author: Shaul Behr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:46:56

Uso de parámetros predeterminados con métodos virtuales

abstract class Base
{
    public virtual void foo(string s = "base") { Console.WriteLine("base " + s); }
}

class Derived : Base
{
    public override void foo(string s = "derived") { Console.WriteLine("derived " + s); }
}

...

Base b = new Derived();
b.foo();

Salida:
base derivada

 28
Author: BlueRaja - Danny Pflughoeft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-14 20:21:17

Objetos de valor en colecciones mutables

struct Point { ... }
List<Point> mypoints = ...;

mypoints[i].x = 10;

No tiene efecto.

mypoints[i] devuelve una copia de un objeto de valor Point. C# felizmente le permite modificar un campo de la copia. Silenciosamente sin hacer nada.


Actualización: Esto parece estar arreglado en C# 3.0:

Cannot modify the return value of 'System.Collections.Generic.List<Foo>.this[int]' because it is not a variable
 27
Author: Bjarke Ebert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-12 14:40:45

Quizás no sea lo peor, pero algunas partes de. net framework usan grados mientras que otras usan radianes (y la documentación que aparece con Intellisense nunca te dice cuál, tienes que visitar MSDN para averiguarlo)

Todo esto podría haberse evitado teniendo una clase Angle en su lugar...

 25
Author: BlueRaja - Danny Pflughoeft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-31 20:46:14

Para los programadores de C/C++, la transición a C# es natural. Sin embargo, el mayor gotcha que he encontrado personalmente (y he visto con otros haciendo la misma transición) es no entender completamente la diferencia entre clases y estructuras en C#.

En C++, las clases y las estructuras son idénticas; solo difieren en la visibilidad predeterminada, donde las clases por defecto son visibilidad privada y las estructuras por defecto son visibilidad pública. En C++, esta definición de clase

    class A
    {
    public:
        int i;
    };

Es funcionalmente equivalente a esta definición de estructura.

    struct A
    {
        int i;
    };

En C#, sin embargo, las clases son tipos de referencia mientras que las estructuras son tipos de valor. Esto hace una GRAN diferencia en (1) decidir cuándo usar uno sobre el otro, (2) probar la igualdad de objetos, (3) rendimiento (por ejemplo, boxear/unboxing), etc.

Hay todo tipo de información en la web relacionada con las diferencias entre los dos (por ejemplo, aquí). Animaría encarecidamente a cualquiera que haga la transición a C # a at menos tener un conocimiento práctico de las diferencias y sus implicaciones.

 22
Author: Matt Davis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-12 21:36:56

Recolección de basura y Dispose(). Aunque no tienes que hacer nada para liberar memoria, todavía tienes que liberar recursos a través de Dispose(). Esto es algo inmensamente fácil de olvidar cuando está utilizando WinForms, o rastreando objetos de cualquier manera.

 19
Author: Jeff Kotula,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-27 20:07:11

Foreach bucles variables alcance!

var l = new List<Func<string>>();
var strings = new[] { "Lorem" , "ipsum", "dolor", "sit", "amet" };
foreach (var s in strings)
{
    l.Add(() => s);
}

foreach (var a in l)
    Console.WriteLine(a());

Imprime cinco "amet", mientras que el siguiente ejemplo funciona bien

var l = new List<Func<string>>();
var strings = new[] { "Lorem" , "ipsum", "dolor", "sit", "amet" };
foreach (var s in strings)
{
    var t = s;
    l.Add(() => t);
}

foreach (var a in l)
    Console.WriteLine(a());
 18
Author: Brian J Cardiff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-27 21:11:24

MS SQL Server no puede manejar fechas anteriores a 1753. Significativamente, eso está fuera de sincronía con la constante.NET DateTime.MinDate, que es 1/1/1. Así que si intentas salvar un mindate, una fecha malformada (como me sucedió recientemente en una importación de datos) o simplemente la fecha de nacimiento de Guillermo el Conquistador, vas a estar en problemas. No hay una solución alternativa incorporada para esto; si es probable que necesite trabajar con fechas anteriores a 1753, debe escribir su propia solución alternativa.

 18
Author: Shaul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-11 13:31:33

Implementación de matricesIList

Pero no lo implementen. Cuando llamas a Add, te dice que no funciona. Entonces, ¿por qué una clase implemente una interfaz cuando no puede apoyar?

Compila, pero no funciona:

IList<int> myList = new int[] { 1, 2, 4 };
myList.Add(5);

Tenemos este problema mucho, porque el serializador (WCF) convierte todas las ILists en matrices y obtenemos errores de tiempo de ejecución.

 17
Author: Stefan Steinegger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-15 15:02:20

El contrato en Curso.Leer es algo que he visto tropezar a mucha gente:

// Read 8 bytes and turn them into a ulong
byte[] data = new byte[8];
stream.Read(data, 0, 8); // <-- WRONG!
ulong data = BitConverter.ToUInt64(data);

La razón por la que esto es incorrecto es que Stream.Read leerá a lo sumo el número especificado de bytes, pero es completamente libre para leer solo 1 byte, incluso si otros 7 bytes están disponibles antes del final de la secuencia.

No ayuda que esto se vea tan similar a Stream.Write, que está garantizado que ha escrito todos los bytes si regresa sin excepción. También no ayuda que el código anterior funcione casi todo el tiempo. Y, por supuesto, no ayuda que no haya un método práctico y listo para leer exactamente N bytes correctamente.

Entonces, para tapar el agujero y aumentar la conciencia de esto, aquí hay un ejemplo de una manera correcta de hacer esto:

    /// <summary>
    /// Attempts to fill the buffer with the specified number of bytes from the
    /// stream. If there are fewer bytes left in the stream than requested then
    /// all available bytes will be read into the buffer.
    /// </summary>
    /// <param name="stream">Stream to read from.</param>
    /// <param name="buffer">Buffer to write the bytes to.</param>
    /// <param name="offset">Offset at which to write the first byte read from
    ///                      the stream.</param>
    /// <param name="length">Number of bytes to read from the stream.</param>
    /// <returns>Number of bytes read from the stream into buffer. This may be
    ///          less than requested, but only if the stream ended before the
    ///          required number of bytes were read.</returns>
    public static int FillBuffer(this Stream stream,
                                 byte[] buffer, int offset, int length)
    {
        int totalRead = 0;
        while (length > 0)
        {
            var read = stream.Read(buffer, offset, length);
            if (read == 0)
                return totalRead;
            offset += read;
            length -= read;
            totalRead += read;
        }
        return totalRead;
    }

    /// <summary>
    /// Attempts to read the specified number of bytes from the stream. If
    /// there are fewer bytes left before the end of the stream, a shorter
    /// (possibly empty) array is returned.
    /// </summary>
    /// <param name="stream">Stream to read from.</param>
    /// <param name="length">Number of bytes to read from the stream.</param>
    public static byte[] Read(this Stream stream, int length)
    {
        byte[] buf = new byte[length];
        int read = stream.FillBuffer(buf, 0, length);
        if (read < length)
            Array.Resize(ref buf, read);
        return buf;
    }
 17
Author: Roman Starkov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-28 22:45:49

El Cacheo Linq Desagradable Gotcha

Ver a mi pregunta que llevó a este descubrimiento, y el blogger que descubrió el problema.

En resumen, el DataContext mantiene una caché de todos los objetos Linq-to-Sql que haya cargado. Si alguien más hace algún cambio en un registro que ha cargado previamente, no podrá obtener los últimos datos, incluso si vuelve a cargar explícitamente el registro!

Esto se debe a una propiedad llamada ObjectTrackingEnabled en el DataContext, que por defecto es true. Si establece esa propiedad en false, el registro se cargará de nuevo cada vez... PERO... no puede persistir ningún cambio en ese registro con SubmitChanges ().

¡TE TENGO!

 17
Author: Shaul Behr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:09:54

Eventos

Nunca entendí por qué los eventos son una característica del lenguaje. Son complicados de usar: necesita verificar null antes de llamar, necesita anular el registro (usted mismo), no puede averiguar quién está registrado (por ejemplo: ¿me registré?). ¿Por qué un evento no es solo una clase en la biblioteca? Básicamente un especializado List<delegate>?

 14
Author: Stefan Steinegger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-15 12:44:42

Los enumerables pueden evaluarse más de una vez

Te morderá cuando tengas un enumerable perezosamente enumerado y lo repitas dos veces y obtengas resultados diferentes. (o se obtienen los mismos resultados pero se ejecuta dos veces innecesariamente)

Por ejemplo, mientras escribía una cierta prueba, necesitaba algunos archivos temporales para probar la lógica:

var files = Enumerable.Range(0, 5)
    .Select(i => Path.GetTempFileName());

foreach (var file in files)
    File.WriteAllText(file, "HELLO WORLD!");

/* ... many lines of codes later ... */

foreach (var file in files)
    File.Delete(file);

Imagina mi sorpresa cuando File.Delete(file) lanza FileNotFound!!

Lo que está sucediendo aquí es que el files enumerable tiene iterated twice (los resultados de la primera iteración son simplemente no recordados) y en cada nueva iteración volverías a llamar a Path.GetTempFilename() por lo que obtendrás un conjunto diferente de nombres de archivo temporales.

La solución es, por supuesto, enumerar el valor usando ToArray() o ToList():

var files = Enumerable.Range(0, 5)
    .Select(i => Path.GetTempFileName())
    .ToArray();

Esto es aún más aterrador cuando estás haciendo algo multihilo, como:

foreach (var file in files)
    content = content + File.ReadAllText(file);

Y usted descubre content.Length sigue siendo 0 después de todas las escrituras!! A continuación, comienza a rigurosamente comprueba que no tienes una condición de carrera cuando.... después de una hora perdida... te diste cuenta de que es sólo esa diminuta cosa enumerable que te olvidaste....

 13
Author: chakrit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-28 14:17:52

Acabo de encontrar una extraña que me tenía atascado en la depuración por un tiempo:

Puede incrementar null para un int nullable sin lanzar una excección y el valor permanece null.

int? i = null;
i++; // I would have expected an exception but runs fine and stays as null
 13
Author: DevDave,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-14 14:53:21

Hoy he corregido un error que se eludió durante mucho tiempo. El error estaba en una clase genérica que se usó en un escenario multihilo y se usó un campo int estático para proporcionar sincronización sin bloqueo usando Enclavamiento. El error fue causado porque cada instanciación de la clase genérica para un tipo tiene su propia estática. Así que cada hilo tiene su propio campo estático y no se utilizó un bloqueo como estaba previsto.

class SomeGeneric<T>
{
    public static int i = 0;
}

class Test
{
    public static void main(string[] args)
    {
        SomeGeneric<int>.i = 5;
        SomeGeneric<string>.i = 10;
        Console.WriteLine(SomeGeneric<int>.i);
        Console.WriteLine(SomeGeneric<string>.i);
        Console.WriteLine(SomeGeneric<int>.i);
    }
}

Esto imprime 5 10 5

 13
Author: Pratik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-20 09:49:00
TextInfo textInfo = Thread.CurrentThread.CurrentCulture.TextInfo;

textInfo.ToTitleCase("hello world!"); //Returns "Hello World!"
textInfo.ToTitleCase("hElLo WoRld!"); //Returns "Hello World!"
textInfo.ToTitleCase("Hello World!"); //Returns "Hello World!"
textInfo.ToTitleCase("HELLO WORLD!"); //Returns "HELLO WORLD!"

Sí, este comportamiento está documentado, pero eso ciertamente no lo hace correcto.

 9
Author: BlueRaja - Danny Pflughoeft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-30 01:24:33