Pregunta

Comparar

String.Format("Hello {0}", "World");

con

"Hello {0}".Format("World");

¿Por qué los diseñadores de .Net eligieron un método estático en lugar de un método de instancia?¿Qué opinas?

¿Fue útil?

Solución

En realidad no sé la respuesta, pero sospecho que tiene algo que ver con el aspecto de invocar métodos en cadenas literales directamente.

Si no recuerdo mal (en realidad no verifiqué esto porque no tengo un IDE antiguo a mano), las primeras versiones del IDE de C# tenían problemas para detectar llamadas a métodos en cadenas literales en IntelliSense, y eso tiene un gran impacto en la capacidad de descubrimiento. de la API.Si ese fuera el caso, escribir lo siguiente no le serviría de ninguna ayuda:

"{0}".Format(12);

Si te obligaran a escribir

new String("{0}").Format(12);

Estaría claro que no había ninguna ventaja en hacer del método Formato un método de instancia en lugar de un método estático.

Las bibliotecas .NET fueron diseñadas por muchas de las mismas personas que nos dieron MFC, y la clase String en particular tiene un gran parecido con la clase CString en MFC.MFC tiene un método de formato de instancia (que utiliza códigos de formato de estilo printf en lugar del estilo de llave de .NET), lo cual es doloroso porque no existe un literal CString.Entonces, en una base de código MFC en la que trabajé veo mucho de esto:

CString csTemp = "";
csTemp.Format("Some string: %s", szFoo);

lo cual es doloroso.(No estoy diciendo que el código anterior sea una excelente manera de hacer cosas incluso en MFC, pero esa parece ser la forma en que la mayoría de los desarrolladores del proyecto aprendieron a usar CString::Format).Partiendo de esa herencia, puedo imaginar que los diseñadores de API estaban tratando de evitar ese tipo de situación nuevamente.

Otros consejos

Porque el método Format no tiene nada que ver con el valor actual de una cadena.

Eso es cierto para todo métodos de cadena porque las cadenas .NET son inmutables.

Si no fuera estático, para empezar necesitaría una cadena.

Lo hace:la cadena de formato.

Creo que este es sólo otro ejemplo de los muchos defectos de diseño en la plataforma .NET (y no lo digo como una llama;Todavía encuentro que el marco .NET es superior a la mayoría de los otros marcos).

Bueno, supongo que tienes que ser bastante particular al respecto, pero como dice la gente, tiene más sentido que String.Format sea estático debido a la semántica implícita.Considerar:

"Hello {0}".Format("World"); // this makes it sound like Format *modifies* 
                             // the string, which is not possible as 
                             // strings are immutable.

string[] parts = "Hello World".Split(' ');    // this however sounds right, 
                                             // because it implies that you 
                                             // split an existing string into 
                                             // two *new* strings.

Lo primero que hice cuando actualicé a VS2008 y C#3 fue hacer esto

public static string F( this string format, params object[] args )
{
    return String.Format(format, args);
}

Entonces ahora puedo cambiar mi código de

String.Format("Hello {0}", Name);

a

"Hello {0}".F(Name);

que prefería en ese momento.Hoy en día (2014) no me molesto porque es solo otra molestia seguir agregando eso a cada proyecto aleatorio que creo, o enlace en alguna biblioteca de bolsa de utilidades.

¿En cuanto a por qué lo eligieron los diseñadores de .NET?Quién sabe.Parece completamente subjetivo.Mi dinero está en cualquiera de los dos

  • Copiando Java
  • Al chico que lo escribió en ese momento le gustó subjetivamente más.

Realmente no hay otras razones válidas que pueda encontrar

Creo que es porque Format no toma una cadena per se, sino una "cadena de formato".La mayoría de las cadenas son iguales a cosas como "Bob Smith" o "1010 Main St" o lo que sea y no a "Hola {0}", generalmente solo colocas esas cadenas de formato cuando intentas usar una plantilla para crear otra. string, como un método de fábrica y, por lo tanto, se presta a un método estático.

Creo que es porque es un método de creador (no estoy seguro de si hay un nombre mejor).Todo lo que hace es tomar lo que le das y devolver un objeto de cadena única.No opera sobre un objeto existente.Si no fuera estático, para empezar necesitaría una cadena.

Porque el método Format no tiene nada que ver con el valor actual de una cadena.El valor de la cadena no se utiliza.Toma una cadena y devuelve una.

Quizás los diseñadores de .NET lo hicieron de esta manera porque JAVA lo hizo de esta manera...

Abrazar y extender.:)

Ver: http://discuss.techinterview.org/default.asp?joel.3.349728.40

Las cadenas .NET son inmutables
Por lo tanto, tener un método de instancia no tiene ningún sentido.

Según esa lógica, la clase de cadena no debería tener métodos de instancia que devuelvan copias modificadas del objeto, sin embargo, tiene infinidad (Recortar, ToUpper, etc.).Además, muchos otros objetos del marco también hacen esto.

Estoy de acuerdo en que si lo convirtieran en un método de instancia, Format Parece que sería un mal nombre, pero eso no significa que la funcionalidad no deba ser un método de instancia.

¿Por qué no esto?Es consistente con el resto de el marco .NET

"Hello {0}".ToString("Orion");

Los métodos de instancia son buenos cuando tienes un objeto que mantiene algún estado;el proceso de formatear una cadena no afecta la cadena en la que está operando (lea:no modifica su estado), crea una nueva cadena.

Con los métodos de extensión, ahora puedes tener tu pastel y comértelo también (es decir,puedes usar esta última sintaxis si te ayuda a dormir mejor por la noche).

Creo que, en general, se ve mejor usar String.Format, pero podría ver el sentido de querer tener una función no estática para cuando ya tienes una cadena almacenada en una variable que deseas "formatear".

Además, todas las funciones de la clase de cadena no actúan sobre la cadena, sino que devuelven un nuevo objeto de cadena, porque las cadenas son inmutables.

@Jared:

Los métodos estáticos no sobrecargados y no heredados (como Class.b(a,c)) que toman una instancia como primera variable son semánticamente equivalentes a una llamada a un método (como a.b(c))

No, no lo son.

(Suponiendo que se compila en el mismo CIL, lo cual debería ser así).

Ese es tu error.El CIL producido es diferente.La distinción es que los métodos miembro no se pueden invocar en null valores para que el CIL inserte una verificación contra null valores.Obviamente, esto no se hace en la variante estática.

Sin embargo, String.Format hace no permitir null valores por lo que los desarrolladores tuvieron que insertar un cheque manualmente.Desde este punto de vista, la variante del método de miembros sería técnicamente superior.

Esto es para evitar confusiones con .ToString() métodos.

Por ejemplo:

double test = 1.54d;

//string.Format pattern
string.Format("This is a test: {0:F1}", test );

//ToString pattern
"This is a test: " + test.ToString("F1");

Si Format fuera un método de instancia en una cadena, esto podría causar confusión, ya que los patrones son diferentes.

String.Format() es un método de utilidad para convertir varios objetos en una cadena formateada.

Un método de instancia en una cadena hace algo con esa cadena.

Por supuesto, puedes hacer:

public static string FormatInsert( this string input, params object[] args) {
    return string.Format( input, args );
}

"Hello {0}, I have {1} things.".FormatInsert( "world", 3);

No sé por qué lo hicieron, pero ya no importa:

public static class StringExtension
{
    public static string FormatWith(this string format, params object[] args)
    {
        return String.Format(format, args);
    }
}

public class SomeClass
{
    public string SomeMethod(string name)
    {
        return "Hello, {0}".FormatWith(name);
    }
}

Eso fluye mucho más fácilmente, en mi humilde opinión.

Un gran objetivo de diseño para C# era hacer que la transición de C/C++ a C# fuera lo más fácil posible.Usar la sintaxis de puntos en un literal de cadena se vería muy extraño para alguien con solo experiencia en C/C++, y formatear cadenas es algo que un desarrollador probablemente hará el primer día con el lenguaje.Así que creo que lo hicieron estático para acercarlo a un territorio familiar.

Otra razón para String.Format es la similitud con la función printf desde C.Se suponía que permitiría a los desarrolladores de C cambiar de idioma más fácilmente.

No veo nada malo en que sea estático.

La semántica del método estático me parece tener mucho más sentido.Quizás sea porque es primitivo.Donde las primitivas se utilizan con frecuencia, desea que el código de utilidad para trabajar con ellas sea lo más liviano posible.Además, creo que la semántica es mucho mejor con Cadena.Formato encima "MiCadena BLAH BLAH {0}".Formato ...

Los métodos estáticos no sobrecargados y no heredados (como Class.b(a,c)) que toman una instancia como primera variable son semánticamente equivalentes a una llamada a un método (como a.b(c)), por lo que el equipo de la plataforma hizo un arbitrario, elección estética.(Suponiendo que se compila en el mismo CIL, lo cual debería ser así). La única forma de saberlo sería preguntarles por qué.

Posiblemente lo hicieron para mantener las dos cadenas cerca lexigráficamente, es decir.

String.Format("Foo {0}", "Bar");

en lugar de

"Foo {0}".Format("bar");

Quiere saber a qué están asignados los índices;tal vez pensaron que la parte ".Format" simplemente agrega ruido en el medio.

Curiosamente, el método ToString (al menos para números) es lo opuesto:number.ToString("000") con la cadena de formato en el lado derecho.

No lo he probado todavía, pero puedes crear un método de extensión para lo que quieras.No lo haría, pero creo que funcionaría.

También encuentro String.Format() más en línea con otros métodos estáticos modelados como Int32.Parse(), long.TryParse(), etc.

Tu nube también solo usa un StringBuilder si quieres un formato no estático.StringBuilder.AppendFormat()

String.Format tiene que ser un método estático porque las cadenas son inmutables. Convertirlo en un método de instancia implicaría que podría usarlo para "formatear" o modificar el valor de una cadena existente.Esto no se puede hacer y convertirlo en un método de instancia que devuelva una nueva cadena no tendría sentido.Por tanto, es un método estático.

String.Format toma al menos una cadena y devuelve una cadena diferente.No es necesario modificar la cadena de formato para devolver otra cadena, por lo que no tiene mucho sentido hacerlo (ignorando su formato).Por otro lado, no sería tan difícil hacer String.Format ser una función miembro, excepto que no creo que C# permita funciones miembro constantes como lo hace C++.[Corríjame a mí y a esta publicación si es así.]

Las cadenas .NET son inmutables

Por lo tanto, tener un método de instancia no tiene ningún sentido.

String foo = new String();

foo.Format("test {0}",1); // Makes it look like foo should be modified by the Format method. 

string newFoo = String.Format(foo, 1); // Indicates that a new string will be returned, and foo will be unaltered.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top