una son qué programacion métodos método miembros metodo los instancia estáticos estaticos estatico estatica ejemplo clase c# design oop

c# - son - ¿Por qué IsNan es un método estático en la clase Double en lugar de una propiedad de instancia?



qué son los métodos estáticos (7)

La distinción entre una instancia y una static es un punto fundamental que el lenguaje C # (y Java como usted dice) elige aclarar (en C ++, puede llamar a un método static través de una instancia, pero eso es solo sintaxis - bajo la instancia hood .StaticX es la misma instancia de referencia Class.StaticX.

El paso hacia interfaces fluidas ha comenzado a desentrañar mucho de esto ...

La pregunta está en el título, por qué:

return double.IsNaN(0.6d) && double.IsNaN(x);

En lugar de

return (0.6d).IsNaN && x.IsNaN;

Lo pregunto porque al implementar estructuras personalizadas que tienen un valor especial con el mismo significado que NaN, tiendo a preferir el segundo.

Además, el rendimiento de la propiedad es normalmente mejor ya que evita copiar la estructura en la pila para llamar al método estático IsNaN (Y como mi propiedad no es virtual, no hay riesgo de auto-boxing). De acuerdo, no es realmente un problema para los tipos incorporados ya que el JIT podría optimizar esto fácilmente.

Mi mejor conjetura por el momento es que como no se puede tener tanto la propiedad como el método estático con el mismo nombre en la clase doble, favorecen la sintaxis inspirada en Java. (De hecho, podría tener ambos como uno definir un getter de propiedad get_IsNaN y el otro un método estático IsNaN pero será confuso en cualquier lenguaje .Net que soporte la sintaxis de propiedad)


@Pop Catalin: No estoy de acuerdo con lo que dijiste en:

Si la estructura está pensada para ser segura para subprocesos, los métodos se deben convertir en métodos de instancia solo si realizan operaciones atómicas; de lo contrario, se deberían elegir métodos estáticos.

Aquí hay un pequeño programa que demuestra que los métodos estáticos no resuelven este problema para las estructuras:

using System; using System.Threading; using System.Diagnostics; namespace ThreadTest { class Program { struct SmallMatrix { double m_a, m_b, m_c, m_d; public SmallMatrix(double x) { m_a = x; m_b = x; m_c = x; m_d = x; } public static bool SameValueEverywhere(SmallMatrix m) { return (m.m_a == m.m_b) && (m.m_a == m.m_c) && (m.m_a == m.m_d); } } static SmallMatrix s_smallMatrix; static void Watcher() { while (true) Debug.Assert(SmallMatrix.SameValueEverywhere(s_smallMatrix)); } static void Main(string[] args) { (new Thread(Watcher)).Start(); while (true) { s_smallMatrix = new SmallMatrix(0); s_smallMatrix = new SmallMatrix(1); } } } }

Tenga en cuenta que este comportamiento no se puede observar con valores dobles en un procesador común, ya que la mayoría de las instrucciones x86 tienen una versión que funciona con fragmentos de 64 bits, como movl .

Por lo tanto, la seguridad de los hilos no parece ser una buena razón para que IsNaN sea estático:

  1. El marco debe ser independiente de la plataforma, por lo que no debe presuponer cosas como la arquitectura del procesador. La seguridad de subprocesos IsNaN depende del hecho de que los valores de 64bits siempre se acceden y modifican atómicamente en la arquitectura de destino (y los objetivos del marco compacto no son x86 ...).
  2. IsNaN es inútil por sí mismo y en un contexto donde el hilo múltiple podría acceder a someVar este código no es seguro (independientemente de la seguridad del hilo de IsNaN):

print("code sample"); if (!double.IsNaN(someVar)) Console.WriteLine(someVar);

Lo que quiero decir es que incluso si IsNaN se implementa haciendo comparaciones == con todos los valores posibles de NaN ... (no es realmente posible) ... a quién le importa que el valor evolucione durante la ejecución del método si de todos modos podría haber cambiado una vez el método termina ... o incluso podría ser un valor intermedio que nunca debería haber estado aquí si la arquitectura de destino no es x86 ...

Acceder a valores intrínsecos en dos subprocesos diferentes NO es seguro en general, así que no veo ningún interés en proporcionar una ilusión de seguridad al poner cualquier método estático cuando se trata de estructuras o cualquier otro tipo,


Creo que Marc estaba en la respuesta.

El problema es cuando necesita llamar a métodos de instancia en valuetypes, el valor está encasillado. Esto causaría una grave penalización de rendimiento.


Interesante pregunta; no sé la respuesta, pero si realmente te molesta, podrías declarar un método de extensión, pero aún así usaría la pila, etc.

static bool IsNaN(this double value) { return double.IsNaN(value); } static void Main() { double x = 123.4; bool isNan = x.IsNaN(); }

Sería más agradable (para la sintaxis) si C # tuviera propiedades de extensión, pero lo anterior es aproximadamente lo más cercano que puede obtenerse en este momento, pero de todos modos debería "en línea" bastante bien.

Actualizar; pensando en ello, hay otra diferencia entre estático y instancia; C # siempre llama a los métodos de instancia con " callvirt " en lugar de " call ", incluso si su tipo está sellado y no callvirt NULL. Entonces, ¿tal vez hay un beneficio de rendimiento por tenerlo estático? Afortunadamente, los métodos de extensión todavía cuentan como estáticos, por lo que puede conservar este comportamiento.


Recuerdo las palabras de un mentor, rezando para que cualquier método que no use ninguna otra variable aparte de los parámetros sean métodos estáticos.

Realmente no sé por qué, y no he pensado en lo de atrás, pero lógicamente, parece bueno. Interesado en la respuesta de todos modos ;-)


Los métodos estáticos son seguros para subprocesos, los métodos sobre primitivos generalmente necesitan ser seguros para subprocesos para admitir subprocesos en la plataforma (es decir, al menos a salvo de las condiciones internas de carrera), los métodos de instancia toman un puntero administrado a una estructura, lo que significa que la estructura / primitiva podría ser Modificado concurrentemente mientras el método se ejecuta, por otro lado los métodos estáticos toman una copia de la estructura / primitiva y por lo tanto están a salvo de las condiciones de carrera.

Si la estructura está pensada para ser segura para subprocesos, los métodos se deben convertir en métodos de instancia solo si realizan operaciones atómicas; de lo contrario, se deberían elegir métodos estáticos.

(Como otra opción, se pueden usar métodos de instancia que usan bloqueo pero son más caros que la copia)

Editar: @VirtualBlackFox He preparado un ejemplo para mostrar que los métodos de instancia en las estructuras no son seguras ni siquiera en estructuras inmutables:

using System; using System.Threading; namespace CA64213434234 { class Program { static void Main(string[] args) { ManualResetEvent ev = new ManualResetEvent(false); Foo bar = new Foo(0); Action a = () => bar.Display(ev); IAsyncResult ar = a.BeginInvoke(null, null); ev.WaitOne(); bar = new Foo(5); ar.AsyncWaitHandle.WaitOne(); } } public struct Foo { private readonly int val; public Foo(int value) { val = value; } public void Display(ManualResetEvent ev) { Console.WriteLine(val); ev.Set(); Thread.Sleep(2000); Console.WriteLine(val); } } }

El método de instancia de visualización se imprime: 0 5

a pesar de que la estructura es inmutable. Para los métodos de seguridad de subprocesos, use métodos estáticos.


Double.IsNan sigue el mismo patrón que String.IsNullorEmpty. Este último se comporta como lo hace porque lamentablemente no hay manera de declarar que un método de instancia no virtual debería ser utilizable con un nulo "esto". Si bien tal comportamiento puede ser extraño para los tipos de referencia mutables, sería muy útil para las cosas que tienen que ser tipos de referencia pero que deben comportarse semánticamente como valores inmutables. Por ejemplo, el tipo "Cadena" hubiera sido mucho más conveniente si la invocación de sus propiedades en un objeto nulo se hubiera comportado de manera idéntica a invocarlas en una cadena vacía. Tal como están las cosas, hay un extraño mish-mosh de contextos en los que un objeto de cadena nulo se considerará como una cadena vacía, y aquellos en los que se intenta usar uno generarán un error. Hubiera sido mucho más claro si la cadena se hubiera comportado consistentemente como un tipo de valor que se inicializa en una cadena vacía.