322 votos

¿Qué ' s la esquina más extraña caso ' visto en C# o. net?

Puedo recoger un par de casos de esquina y teasers del cerebro y siempre quiere saber más. La página, realmente, sólo cubre el lenguaje C# de bits y bobs, pero también me parece núcleo .NET cosas interesantes también. Por ejemplo, aquí está uno que no está en la página, pero lo que me parece increíble:

string x = new string(new char[0]);
string y = new string(new char[0]);
Console.WriteLine(object.ReferenceEquals(x, y));

Yo esperaría que a impresión Falsa - después de todo, la "nueva" (con un tipo de referencia) siempre se crea un nuevo objeto, ¿no? Las especificaciones para C# y CLI indicar que se debe. Bueno, no en este caso en particular. Imprime Cierto, y lo ha hecho en cada versión del marco de trabajo lo he probado. (Yo no lo he probado en Mono, todo hay que decirlo...)

Sólo para ser claro, esto es sólo un ejemplo de la clase de cosa que estoy buscando - yo no estaba particularmente mirando para el debate/explicación de esta rareza. (No es lo mismo como normal cadena de la internación; en particular, la cadena de la internación no suele suceder cuando un constructor es llamado.) Yo en realidad estaba pidiendo similar comportamiento extraño.

Cualquier otro gemas acechando ahí fuera?

395voto

Marc Gravell Puntos 482669

Creo que ya comenté esto antes, pero me gusta la diversión aquí - esto me tomó algo de depuración para el seguimiento de la pista! (el código original fue obviamente más complejo y sutil...)

    static void Foo<T>() where T : new()
    {
        T t = new T();
        Console.WriteLine(t.ToString()); // works fine
        Console.WriteLine(t.GetHashCode()); // works fine
        Console.WriteLine(t.Equals(t)); // works fine

        // so it looks like an object and smells like an object...

        // but this throws a NullReferenceException...
        Console.WriteLine(t.GetType());
    }

Entonces, ¿qué fue T...

Respuesta: cualquiera Nullable<T> - como int?. Todos los métodos son anuladas, excepto GetType (), que no puede ser, así que se echa (en caja) a objeto (y, por tanto, nulo) para llamar a object.GetType()... lo que pide null ;-p


Actualización: la cosa se complica... Ayende Rahien la tiró a un reto similar en su blog, pero con un where T : class, new():

private static void Main() {
    CanThisHappen<MyFunnyType>();
}

public static void CanThisHappen<T>() where T : class, new() {
    var instance = new T(); // new() on a ref-type; should be non-null, then
    Debug.Assert(instance != null, "How did we break the CLR?");
}

Pero puede ser derrotado! Utilizando el mismo procedimiento indirecto utilizado por cosas como remotos; advertencia : el siguiente es el mal en estado puro:

class MyFunnyProxyAttribute : ProxyAttribute {
    public override MarshalByRefObject CreateInstance(Type serverType) {
        return null;
    }
}
[MyFunnyProxy]
class MyFunnyType : ContextBoundObject { }

Con esto, la new() de llamada se redirige al servidor proxy (MyFunnyProxyAttribute), que devuelve null. Ahora ve y lávate de tus ojos!

216voto

Samuel Kim Puntos 3107

Redondeo de los banqueros.

Ésta no es tanto un error de compilador o mal funcionamiento, pero sin duda un caso raro de la esquina...

El .net Framework emplea un esquema o redondeo conocido como banquero redondeo.

En el redondeo de los banqueros los números 0,5 se redondean al número par más cercano, así

Math.Round(-0.5) == 0
Math.Round(0.5) == 0
Math.Round(1.5) == 2
Math.Round(2.5) == 2
etc...

Esto puede conducir a algunos errores inesperados en los cálculos financieros basados en el redondeo de Half-Round-Up más conocida.

Esto también es cierto de Visual Basic.

176voto

Greg Beech Puntos 55270

¿Qué será de esta función ¿si se llama como Rec(0) (no bajo el depurador)?

static void Rec(int i)
{
    Console.WriteLine(i);
    if (i < int.MaxValue)
    {
        Rec(i + 1);
    }
}

Respuesta:

  • En 32-bits JIT debe resultar en un StackOverflowException
  • En la versión de 64 bits JIT se debe imprimir todos los números para int.MaxValue

Esto es debido a que la versión de 64 bits compilador JIT se aplica la cola de la llamada optimización, mientras que el de 32 bits JIT no.

Lamentablemente no tengo una máquina de 64 bits a mano para comprobarlo, pero el método no cumple con todas las condiciones para la cola de la llamada optimización. Si alguien tiene uno me interesaría ver si es verdad.

113voto

Omer Mor Puntos 3658

Asignar este!

Este es uno que me gustaría preguntar en las fiestas (que probablemente es por qué no me invitan ya):

¿Puedes hacer el siguiente fragmento de código compila?

    public void Foo()
    {
        this = new Teaser();
    }

Un truco fácil podría ser:

string cheat = @"
    public void Foo()
    {
        this = new Teaser();
    }
";

Pero la verdadera solución es:

public struct Teaser
{
    public void Foo()
    {
        this = new Teaser();
    }
}

Así que es un poco hecho que valoren los tipos (structs) puede reasignar sus this variable.

100voto

Jarek Kardas Puntos 6956

Hace unos años, cuando se trabaja en el programa de lealtad, hemos tenido un problema con la cantidad de puntos otorgados a los clientes. El problema estaba relacionado con la difusión de conversión doble para int.

En el código a continuación:

double d = 13.6;

int i1 = Convert.ToInt32(d);
int i2 = (int)d;

¿i1 == i2 ?

Resulta que i1 != i2. Debido a las diferencias de redondeo de las políticas en Convertir y el operador de conversión los valores reales son:

i1 == 14
i2 == 13

Siempre es mejor llamar a Math.Ceiling() o Math.Floor() (o Math.Round con MidpointRounding que cumple los requisitos)

int i1 = Convert.ToInt32( Math.Ceiling(d) );
int i2 = (int) Math.Ceiling(d);

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by: