2008-08-22 18 views

Respuesta

27

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

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

"{0}".Format(12); 

si se vieron obligados a escribir

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

Sería claro que no había ninguna ventaja para hacer el formato método un método de instancia en lugar de un método estático.

Las bibliotecas .NET fueron diseñadas por una gran cantidad 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 usa códigos de formato de estilo de impresión en lugar del estilo de llaves rizadas de .NET), lo cual es doloroso porque no existe un literal de CString. Así que en una base de código MFC en la que trabajé veo mucho de esto:

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

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

+5

... ¿Así que está diseñado de esa manera debido a la incompetencia del diseño IDE? –

+0

Entonces, ¿por qué no agregarían el formulario '" ".Format' más adelante, ahora que el IDE es mejor? No se rompe nada por lo que sé. –

5

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

4

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

1

veo nada de malo en que sea estática ..

La semántica del método estático parece tener mucho más sentido para mí. Tal vez es porque es un primitivo. Cuando se usan primitivas con frecuencia, se debe hacer que el código de utilidad para trabajar con ellas sea lo más claro posible. Además, creo que la semántica es mucho mejor con String.Format sobre "MyString BLAH BLAH {0}" .Formato ...

+0

No hay nada de malo en que sea estático; Mi razón para preguntarme sobre esto es que agrega longitud en comparación con '" mi {0} cadena ".Format (args)', y complica el cambio de un literal de cadena a una cadena formateada. No por mucho, pero lo suficiente como para que un método de instancia sea útil. – ehdv

2

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

Con los métodos de extensión, ahora puede tener su pastel y comerlo también (es decir, puede usar la última sintaxis si le ayuda a dormir mejor por la noche).

1

No lo he intentado todavía, pero podría hacer un método de extensión para lo que desee. 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 estampadas como Int32.Parse(), long.TryParse(), etc.

Se nubla también sólo tiene que utilizar un StringBuilder si quieres un formato no estático. StringBuilder.AppendFormat()

-1

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 tiene poco sentido hacer eso (ignorando el formateo de la misma). Por otro lado, no sería demasiado exagerado hacer que String.Format sea una función miembro, excepto que no creo que C# permita funciones de miembros const como C++. [Por favor corrígeme y esta publicación si lo hace.]

2

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

Como un lado, todas las funciones de la clase de cadena no actúan en la cadena, sino que devuelven un nuevo objeto de cadena, porque las cadenas son inmutables.

46

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

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

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

Lo hace: la cadena de formato.

Creo que este es solo otro ejemplo de los muchos defectos de diseño en la plataforma .NET (y no me refiero a esto como una llama, todavía encuentro el .NET framework superior a la mayoría de los otros frameworks).

+1

¿por qué no es esta la respuesta aceptada? – Tim

+1

@tim: porque creo que la respuesta de Andrews es mejor. :-) –

+2

De hecho, también prefiero la respuesta aceptada, ya que responde perfectamente a la pregunta. Mi propia respuesta es más como un comentario a algunas de las suposiciones que se tienen sobre el diseño de funciones estáticas. –

1

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 devolvió una nueva cadena no tendría sentido. Por lo tanto, es un método estático.

+8

¿En qué se diferencia el formato de Replace o Substring? No se cambian las cadenas reales, se devuelven las nuevas. Format podría haber seguido el ejemplo. – Greg

+0

Es cierto, pero piense de esta manera: si el formato fuera un método de instancia, tendría que declarar su cadena y luego llamar a Format. Siempre sería un proceso de dos pasos. P.ej. 1) cadena strTemp; 2) strTemp.Format ("{0}", "Hola mundo"); Más limpio para hacerlo estático. –

+0

Y semánticamente hablando, Reemplazar y Subcadena tienen sentido como métodos de instancia. El formato podría haber ido de cualquier manera pero el uso es más limpio si es estático. –

9

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

"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. 
+5

Su segundo ejemplo realmente se descompone para cosas como '" a b c ". Reemplazar (" a "," gatito ")', IMO. – notJim

4

Tal vez los diseñadores .NET hecho durante esta manera porque JAVA hizo de esta manera ...

adoptar y extender. :)

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

+0

AFAIK el método .NET es anterior al método Java (Java solo lo obtuvo en la Versión 5). –

+0

¿eh? Java 1.5: http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html#format (java.lang.String,% 20java.lang.Object ...) –

+0

@jm: por raras razones de mercadeo conocidas por Sun, Java 1.5 y Java 5 son lo mismo. –

8

La primera cosa que hice cuando llegué a actualizar a VS2008 y C# 3, era para hacer esto

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

Así que ahora puedo cambiar mi código de

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

a

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

que preferí en ese momento. Hoy en día (2014) no me molesto porque no es más que otra molestia volver a agregar eso a cada proyecto aleatorio que creo, o vincularlo en alguna biblioteca de bolsa de utilidades.

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

  • Copia de Java
  • El tipo de escribirlo en el momento subjetivamente gustó más.

En realidad no hay otras razones válidas que puedo encontrar

+2

No creo que el método de extensión sea el correcto. Creo un momento de trabajo para el lector. Creo que en C# estamos atrapados con la versión estática. –

+1

Eso es subjetivo, @Jakub. Para mí, sé lo que es instantáneamente correcto cuando veo llaves rizadas. –

+2

No estoy seguro de qué es un "momento de trabajo", pero ¿cómo es esto diferente de cualquier otro uso de métodos de extensión? – Ken

-2

.NET Las cadenas son inmutables

Por 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. 
1

métodos estáticos para no sobrecargado, no hereditaria (como Class.b (a, c)) que tienen una instancia como la primera variable son semánticamente equivalente a una llamada al método (como ab (c)) de modo el equipo de la plataforma hizo una elección arbitraria y estética. (Suponiendo que compila al mismo CIL, lo que debería hacer). La única forma de saberlo sería preguntarles por qué.

Posiblemente lo hicieron para mantener las dos cuerdas cerca uno del otro lexigraphically, es decir

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

en lugar de

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

¿Quieres saber cuáles son los índices se asignan a; quizás pensaron que la parte ".Format" simplemente agrega ruido en el medio.

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

3

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

Con esa lógica la clase string no debería tener métodos de instancia que devuelven copias modificadas del objeto, sin embargo, tiene un montón (Trim, ToUpper, y así sucesivamente). Además, muchos otros objetos en el marco también lo hacen.

Acepto que si lo convirtieran en un método de instancia, Format parece que sería un nombre incorrecto, pero eso no significa que la funcionalidad no deba ser un método de instancia.

¿Por qué no esto? Es consistente con the rest ofthe .NET framework

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

@Jared:

métodos estáticos para no sobrecargado, no hereditaria (como Class.b (a, c)) que tienen una instancia como la primera variable son semánticamente equivalente a una llamada a método (como ab (c))

No, no lo son.

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

Ese es su error. El CIL producido es diferente. La diferencia es que los métodos miembro no pueden invocarse en los valores null, por lo que el CIL inserta una marca en los valores null. Obviamente, esto no se hace en la variante estática.

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

+2

Creo que fue un paradigma muy útil cuando alguien (Python) me dijo que pensara en funciones de miembro como funciones estáticas con un objeto 'this' explícito como primer elemento. ¡Gracias por el comentario sobre nulls! Por cierto, la sobrecarga agrega más complicaciones a la equivalencia del método estático/miembro. –

2

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

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 el formato era un método de instancia en la cadena de 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, se podría 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); 
2

No sé por qué lo hicieron, pero realmente no importa más:

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); 
    } 
} 

que fluye mucho más fácil, EN MI HUMILDE OPINIÓN.

2

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

2

Un gran objetivo de diseño para C# era hacer que la transición de C/C++ a lo más fácil posible. El uso de la sintaxis de punto en un literal de cadena sería muy extraño para alguien con solo un fondo C/C++, y el formateo de cadenas es algo que un desarrollador probablemente haga el primer día con el lenguaje. Así que creo que hicieron que sea estático hacerlo más cercano al territorio familiar.

6

Creo que es porque el formato 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 es lo mismo que "Hola {0}", generalmente solo ingresas esas cadenas de formato cuando estás tratando de usar una plantilla para crear otra cadena, como un método de fábrica, y por lo tanto se presta a un método estático.

+0

Esta parece ser la mejor respuesta hasta el momento. Sin embargo, si se supone que es 'diferente de una cadena ', entonces ¿por qué ponerlo en la clase String en absoluto ... –

Cuestiones relacionadas