¿Cuáles son sus métodos de extensión favoritos para C #? (codeplex.com/extensionoverflow)

478

Hagamos una lista de respuestas donde publique sus métodos de extensión excelentes y favoritos .

El requisito es que se debe publicar el código completo y un ejemplo y una explicación sobre cómo usarlo.

Basado en el gran interés en este tema, he configurado un proyecto de código abierto llamado extensionoverflow en Codeplex .

Marque sus respuestas con una aceptación para incluir el código en el proyecto Codeplex.

Publique el código fuente completo y no un enlace.

Noticias Codeplex:

24.08.2010 La página de Codeplex ahora está aquí: http://extensionoverflow.codeplex.com/

11.11.2008 XmlSerialize / XmlDeserialize ahora se implementa y se prueba la unidad .

11.11.2008 Todavía hay espacio para más desarrolladores. ;-) ¡ Únete AHORA!

11.11.2008 El tercer contribuyente se unió a ExtensionOverflow , bienvenido a BKristensen

11.11.2008 FormatWith ahora se implementa y se prueba la unidad .

09.11.2008 El segundo contribuyente se unió a ExtensionOverflow . bienvenido a chakrit .

09.11.2008 Necesitamos más desarrolladores. ;-)

09.11.2008 ThrowIfArgumentIsNull en ahora implementado y probado en Codeplex.

bovium
fuente
Ahora el primer código está comprometido con el sitio de Codeplex.
Bovium
Erik desafortunadamente todo comenzó ahora en codeplex. Por favor únete de todos modos.
Bovium
3
Se ve bastante bien. Tengo un comentario sobre nombrar las clases estáticas. Nombrarlas Extensiones <tipo> no es muy informativo. Por ejemplo, StringExtensions contiene tanto el formato como el contenido xml. Creo que es mejor nombrar a la clase por qué estás extendiendo ese tipo. Por ejemplo, UnixDateTimeConversions. Puede suponer razonablemente que posee métodos para convertir ay desde tiempo Unix. ¡Solo un pensamiento!
ecoffey
Consulte esta URL para obtener más información sobre los métodos de extensión de C # planetofcoders.com/c-extension-methods
Gaurav Agrawal

Respuestas:

232
public static bool In<T>(this T source, params T[] list)
{
  if(null==source) throw new ArgumentNullException("source");
  return list.Contains(source);
}

Me permite reemplazar:

if(reallyLongIntegerVariableName == 1 || 
    reallyLongIntegerVariableName == 6 || 
    reallyLongIntegerVariableName == 9 || 
    reallyLongIntegerVariableName == 11)
{
  // do something....
}

and

if(reallyLongStringVariableName == "string1" || 
    reallyLongStringVariableName == "string2" || 
    reallyLongStringVariableName == "string3")
{
  // do something....
}

and

if(reallyLongMethodParameterName == SomeEnum.Value1 || 
    reallyLongMethodParameterName == SomeEnum.Value2 || 
    reallyLongMethodParameterName == SomeEnum.Value3 || 
    reallyLongMethodParameterName == SomeEnum.Value4)
{
  // do something....
}

Con:

if(reallyLongIntegerVariableName.In(1,6,9,11))
{
      // do something....
}

and

if(reallyLongStringVariableName.In("string1","string2","string3"))
{
      // do something....
}

and

if(reallyLongMethodParameterName.In(SomeEnum.Value1, SomeEnum.Value2, SomeEnum.Value3, SomeEnum.Value4)
{
  // do something....
}
Winston Smith
fuente
2
Bueno, se compila si estás usando System.Linq;
Ryu
11
¿Quizás "EqualsAnyOf" sería un nombre mejor que "In"?
Tom Bushell
10
No estoy seguro de que me guste, me gusta la brevedad de In, pero tal vez IsInsería mejor.
Winston Smith
50
Usando el mismo método Contiene: (nuevo [] {1, 2, 3}) Contiene (a)
Max Toro
44
También lo pensé In<T>(...)y descubrí que es el método de extensión más útil fuera de la biblioteca estándar. Pero estoy en desacuerdo con el nombre In. Se supone que el nombre de un método describe lo que hace, pero Inno lo hace. Lo he llamado IsAnyOf<T>(...), pero supongo IsIn<T>(...)que también sería adecuado.
JBSnorro
160

Tengo varios métodos de extensión en mi proyecto MiscUtil (la fuente completa está disponible allí, no la voy a repetir aquí). Mis favoritos, algunos de los cuales involucran otras clases (como rangos):

Fecha y hora, principalmente para pruebas unitarias. No estoy seguro de usarlos en producción :)

var birthday = 19.June(1976);
var workingDay = 7.Hours() + 30.Minutes();

Rangos y pasos: muchas gracias a Marc Gravell por sus cosas de operador para hacer esto posible:

var evenNaturals = 2.To(int.MaxValue).Step(2);
var daysSinceBirth = birthday.To(DateTime.Today).Step(1.Days());

Comparaciones:

var myComparer = ProjectionComparer.Create(Person p => p.Name);
var next = myComparer.ThenBy(p => p.Age);
var reversed = myComparer.Reverse();

Comprobación de argumentos:

x.ThrowIfNull("x");

LINQ to XML aplicado a tipos anónimos (u otros tipos con propiedades apropiadas):

// <Name>Jon</Name><Age>32</Age>
new { Name="Jon", Age=32}.ToXElements();
// Name="Jon" Age="32" (as XAttributes, obviously)
new { Name="Jon", Age=32}.ToXAttributes()

Presione LINQ: tomaría demasiado tiempo explicarlo aquí, pero búsquelo.

Jon Skeet
fuente
1
¡Eso es bueno! Debería ponerlo en Google Code o CodePlex para que pueda enviarle algunos parches :-) Prometo que será legible
:-P
3
@bovium: ya puedes ver el código. Siga el enlace en la primera oración: la fuente completa está allí.
Jon Skeet
1
@bovium: prefiero hacerlo yo mismo, ponerlo en code.google.com y administrar el proyecto yo mismo, si no le importa. Obviamente estás dentro de la licencia para ponerlo en Codeplex si mantienes la atribución apropiada, pero prefiero resolverlo pronto a menos que estés desesperado :)
Jon Skeet
1
@ Jon Skeet. Se coloca bajo la licencia MIT de forma gratuita para todos. Comercialmente o de código abierto. ¿Por qué no unir fuerzas y crear una biblioteca de métodos de extensión para el público?
Bovium
1
Solo porque hago muchos otros fragmentos en esa biblioteca. Puede tomar una copia de todo para su proyecto, pero prefiero guardar una copia en mi propio proyecto también.
Jon Skeet
147

cadena. Atajo de formato:

public static class StringExtensions
{
    // Enable quick and more natural string.Format calls
    public static string F(this string s, params object[] args)
    {
        return string.Format(s, args);
    }
}

Ejemplo:

var s = "The co-ordinate is ({0}, {1})".F(point.X, point.Y);

Para copiar y pegar rápidamente, vaya aquí .

¿No le parece más natural escribir en "some string".F("param")lugar de string.Format("some string", "param")?

Para obtener un nombre más legible , pruebe una de estas sugerencias:

s = "Hello {0} world {1}!".Fmt("Stack", "Overflow");
s = "Hello {0} world {1}!".FormatBy("Stack", "Overflow");
s = "Hello {0} world {1}!".FormatWith("Stack", "Overflow");
s = "Hello {0} world {1}!".Display("Stack", "Overflow");
s = "Hello {0} world {1}!".With("Stack", "Overflow");

..

revs chakrit
fuente
11
Ciertamente es breve, pero será ilegible para cualquier miembro nuevo de su equipo.
Jon Skeet
3
Creo que la legibilidad importa más en el esquema más amplio de su código que unas pocas declaraciones abreviadas que podrían consultarse / preguntarse rápidamente.
chakrit
66
Personalmente, me gustaría un objeto formateador separado, que el BCL podría analizar el patrón de una vez y reutilizar. Eso aumentaría la legibilidad y el rendimiento. Le pregunté al equipo de BCL - ya veremos ...
Jon Skeet
3
Es un método de extensión, por supuesto , será ilegible para los nuevos miembros del equipo. ¿Pensé que esa era la idea con estas cosas ingeniosas? ¿De qué otra forma sabrán los nuevos miembros lo inteligentes que somos?
MarkJ
17
Ok ... Fui a poner esto en acción y fui con .With - así que obtienes "Esto es un {0}". Con ("test") y es muy legible y tiene sentido. FYI
klkitchens
89

¿Son de alguna utilidad?

public static bool CoinToss(this Random rng)
{
    return rng.Next(2) == 0;
}

public static T OneOf<T>(this Random rng, params T[] things)
{
    return things[rng.Next(things.Length)];
}

Random rand;
bool luckyDay = rand.CoinToss();
string babyName = rand.OneOf("John", "George", "Radio XBR74 ROCKS!");
xyz
fuente
esto imita la función pythons random.choice (seq). bonito.
Daren Thomas
66
Un par de cosas: recomendaría que OneOfacepte alguno IList<T> . Entonces siempre se puede también tener una sobrecarga que toma un paramsarg y simplemente pasa que en la IList<T>sobrecarga. Di una respuesta (ahora en la parte inferior en este momento) con un NextBoolmétodo similar al tuyo CoinToss, pero con una sobrecarga que requiere un probabilityparámetro (¿qué pasa si quiero que ocurra algo el 75% del tiempo?). Además, solo una selección: tu código de ejemplo arrojará un NullReferenceExceptiondado randque nunca se inicializa.
Dan Tao
3
+1 Realmente me gusta esto, pero prefiero CoinTossque se implemente con rng.NextDouble() < .5porque internamente .Next(int)está hecho .NextDouble()para que pueda guardar un elenco, un * y un cheque.
Lasse Espeholt
76
public static class ComparableExtensions
{
  public static bool Between<T>(this T actual, T lower, T upper) where T : IComparable<T>
  {
    return actual.CompareTo(lower) >= 0 && actual.CompareTo(upper) < 0;
  }
}

Ejemplo:

if (myNumber.Between(3,7))
{
  // ....
}
CMS
fuente
19
Me encanta este, pero estoy tratando de decidir si es correcto hacer que los límites verifiquen el valor mínimo pero no el valor máximo. Me pregunto si eso sería confuso. 5.Entre (5,10) es verdadero pero 5.Entre (1,5) es falso. Ni siquiera estoy seguro de que un método interno de compañero sería útil. Thougts?
Steve Hiner, el
12
¿No tendría más sentido el nombre "IsBetween"? También puede hacer un IsBetweenInclusive y IsBetweenExclusive. Sin embargo, no tengo idea de cuál tomar por defecto.
fretje
2
@Steve: tiene más sentido si fuera una extensión de fecha y hora.
Joel Coehoorn
16
Para mí, entre implica: 5.Entre (5,10) devuelve falso, y 10.Entre (5,10) también devuelve falso. Eso me parece natural.
Alex Baranosky
3
Me parece que varias personas tienen ideas diferentes sobre lo que es natural. Debido a esto, probablemente debería indicarse explícitamente qué se está utilizando (es decir, inclusivo frente a exclusivo), ya que podría ser una fuente muy fácil de errores.
David Miani
58

El método de extensión:

public static void AddRange<T, S>(this ICollection<T> list, params S[] values)
    where S : T
{
    foreach (S value in values)
        list.Add(value);
}

El método se aplica a todos los tipos y le permite agregar un rango de elementos a una lista como parámetros.

Ejemplo:

var list = new List<Int32>();
list.AddRange(5, 4, 8, 4, 2);
stiduck
fuente
15
Sería mejor ya que esta lista <T>
21
Solo use el inicializador de colección =>var list = new List<int>{5,4,8,4,2};
Arnis Lapsa
¿Por qué no simplemente llamar a List <T> .AddRange (colección IEnumerable <T>) dentro de su método?
Rauhotz
8
@Will: En realidad, sería mejor aceptar un ICollection<T>; entonces también podría usarse, por ejemplo, LinkedList<T>y HashSet<T>no solo en colecciones indexadas.
Dan Tao
2
Editado para permitir la covarianza en pre.net 4.0
BlueRaja - Danny Pflughoeft
55

Por supuesto, pon esto en el proyecto codeplex.

Serializar / Deserializar objetos a XML:

/// <summary>Serializes an object of type T in to an xml string</summary>
/// <typeparam name="T">Any class type</typeparam>
/// <param name="obj">Object to serialize</param>
/// <returns>A string that represents Xml, empty otherwise</returns>
public static string XmlSerialize<T>(this T obj) where T : class, new()
{
    if (obj == null) throw new ArgumentNullException("obj");

    var serializer = new XmlSerializer(typeof(T));
    using (var writer = new StringWriter())
    {
        serializer.Serialize(writer, obj);
        return writer.ToString();
    }
}

/// <summary>Deserializes an xml string in to an object of Type T</summary>
/// <typeparam name="T">Any class type</typeparam>
/// <param name="xml">Xml as string to deserialize from</param>
/// <returns>A new object of type T is successful, null if failed</returns>
public static T XmlDeserialize<T>(this string xml) where T : class, new()
{
    if (xml == null) throw new ArgumentNullException("xml");

    var serializer = new XmlSerializer(typeof(T));
    using (var reader = new StringReader(xml))
    {
        try { return (T)serializer.Deserialize(reader); }
        catch { return null; } // Could not be deserialized to this type.
    }
}
TWith2Sugars
fuente
8
Estaría tentado a llamar al primero ToXml()(como ToString())
Jay Bazuzi
1
Disculpas al OP si lo escribió intencionalmente de esta manera, pero el uso de MemoryStreams AND XmlReader / XmlWriter fue excesivo. Las clases StringReader y StringWriter son perfectas para esta operación.
Portman el
2
Cuidado, esto no es seguro. Definitivamente debe sincronizar su acceso al diccionario de serializadores estáticos.
Yann Schwartz
2
@Yann, @T, es mucho más fácil si solo agrega el atributo "hilo estático". Luego se creará un nuevo caché por hilo. No hay necesidad de sincronización.
Frank Krueger el
1
@ Jonathan C Dickinson: De los documentos de MSDN aquí msdn.microsoft.com/en-us/library/… parece que el constructor que se usa (nuevo XmlSerializer (tipo)) no tiene un problema de pérdida de memoria. Entonces, ¿tal vez no se necesita el código de almacenamiento en caché?
slolife
46

ForEach para IEnumerables

public static class FrameworkExtensions
{
    // a map function
    public static void ForEach<T>(this IEnumerable<T> @enum, Action<T> mapFunction)
    {
        foreach (var item in @enum) mapFunction(item);
    }
}

Ejemplo ingenuo:

var buttons = GetListOfButtons() as IEnumerable<Button>;

// click all buttons
buttons.ForEach(b => b.Click());

Buen ejemplo:

// no need to type the same assignment 3 times, just
// new[] up an array and use foreach + lambda
// everything is properly inferred by csc :-)
new { itemA, itemB, itemC }
    .ForEach(item => {
        item.Number = 1;
        item.Str = "Hello World!";
    });

Nota:

Esto no es así Selectporque Select espera que su función devuelva algo como para transformarse en otra lista.

ForEach simplemente le permite ejecutar algo para cada uno de los elementos sin ninguna transformación / manipulación de datos.

Hice esto para poder programar en un estilo más funcional y me sorprendió que List tenga un ForEach mientras que IEnumerable no.

Pon esto en el proyecto codeplex

revs chakrit
fuente
13
Publique sobre por qué las extensiones IEnumerable <T> de LINQ no incluyen ForEach: stackoverflow.com/questions/317874/…
Neil
13
Recomiendo leer esto antes de usar el método: blogs.msdn.com/ericlippert/archive/2009/05/18/…
jpbochi
2
@jpbochi: Esto es solo demagogia de Microsoft
abatishchev
1
@abatishchev Y tu comentario es solo un prejuicio contra Microsoft. No invalida ninguna palabra escrita por Eric. Los argumentos de alguien no se hacen válidos o inválidos solo por la empresa para la que trabaja.
jpbochi
1
Por cierto, déjenme aclarar un punto. No dije que no debería usar este método de extensión ForEach. Acabo de decir que debes considerar los puntos que Eric expuso antes de decidir si usarlo o no. Lo leí y decidí no usarlo. Eres libre de hacer lo que quieras con tu código.
jpbochi
43

Mis extensiones de conversión que te permiten hacer:

int i = myString.To<int>();

Aquí está, según lo publicado en TheSoftwareJedi.com

public static T To<T>(this IConvertible obj)
{
  return (T)Convert.ChangeType(obj, typeof(T));
}

public static T ToOrDefault<T>
             (this IConvertible obj)
{
    try
    {
        return To<T>(obj);
    }
    catch
    {
        return default(T);
    }
}

public static bool ToOrDefault<T>
                    (this IConvertible obj,
                     out T newObj)
{
    try
    {
        newObj = To<T>(obj); 
        return true;
    }
    catch
    {
        newObj = default(T); 
        return false;
    }
}

public static T ToOrOther<T>
                       (this IConvertible obj,
                       T other)
{
  try
  {
      return To<T>obj);
  }
  catch
  {
      return other;
  }
}

public static bool ToOrOther<T>
                         (this IConvertible obj,
                         out T newObj,
                         T other)
{
    try
    {
        newObj = To<T>(obj);
        return true;
    }
    catch
    {
        newObj = other;
        return false;
    }
}

public static T ToOrNull<T>
                      (this IConvertible obj)
                      where T : class
{
    try
    {
        return To<T>(obj);
    }
    catch
    {
        return null;
    }
}

public static bool ToOrNull<T>
                  (this IConvertible obj,
                  out T newObj)
                  where T : class
{
    try
    {
        newObj = To<T>(obj);
        return true;
    }
    catch
    {
        newObj = null;
        return false;
    }
}

Puede solicitar el valor predeterminado (llama al constructor en blanco o "0" para los números) en caso de error, especificar un valor "predeterminado" (lo llamo "otro") o solicitar un valor nulo (donde T: clase). También proporcioné modelos de excepción silenciosa y un modelo típico de TryParse que devuelve un valor de bool que indica la acción tomada, y un parámetro de salida contiene el nuevo valor. Entonces nuestro código puede hacer cosas como esta

int i = myString.To<int>();
string a = myInt.ToOrDefault<string>();
//note type inference
DateTime d = myString.ToOrOther(DateTime.MAX_VALUE);
double d;
//note type inference
bool didItGiveDefault = myString.ToOrDefault(out d);
string s = myDateTime.ToOrNull<string>();

No pude hacer que los tipos Nullable se integraran de manera muy limpia. Lo intenté durante unos 20 minutos antes de tirar la toalla.

TheSoftwareJedi
fuente
64
Personalmente, no soy un fanático del código que intenta / captura para determinar el resultado. Try / catch debe usarse para errores que ocurren fuera de la lógica prevista, IMO. hmmmmm
Pure.Krome
Si no quisiera que usaras el código, ¡no lo habría publicado! :)
TheSoftwareJedi
Finalmente algo invisible. Me gusta. :)
Arnis Lapsa el
8
Al menos debe cambiar esa cláusula "catch" para capturar solo las excepciones que ChangeType () generará cuando no pueda "convertir" la referencia. Creo que no querrá que se reciba ninguna excepción OutOfMemoryException, ExecutionEngineException, ThreadAbortException o similar como un error de conversión. De lo contrario, esas cosas serán bastante difíciles de rastrear errores.
Christian.K
2
Creo que ToOrNulltiene exactamente el mismo comportamiento que ToOrDefault(es decir, si llama ToOrDefaulta un tipo de referencia con una conversión fallida, volverá null). Pero lo que es más importante, me parece algo redundante, ya que var s = myObject as stringlogra lo mismo que var s = myObject.ToOrNull<string>(), pero sin tener que atraparlo InvalidCastException. ¿Me estoy perdiendo de algo?
Dan Tao
43

Tengo un método de extensión para registrar excepciones:

public static void Log(this Exception obj)
{
  //your logging logic here
}

Y se usa así:

try
{
    //Your stuff here
}
catch(Exception ex)
{
    ex.Log();
}

[perdón por publicar dos veces; el segundo está mejor diseñado :-)]

Charlie
fuente
2
¿Debería leer el registro público de vacío estático (esta excepción obj) {} tal vez?
Chris S
Creo que esto es bueno para BCL o excepciones de terceros, pero si coloca sus propios tipos de excepción, puede colocar el registro en su clase de excepción base. De esa manera no tiene que recordar llamar a Log ().
si618
38
public static class StringExtensions {

    /// <summary>
    /// Parses a string into an Enum
    /// </summary>
    /// <typeparam name="T">The type of the Enum</typeparam>
    /// <param name="value">String value to parse</param>
    /// <returns>The Enum corresponding to the stringExtensions</returns>
    public static T EnumParse<T>(this string value) {
        return StringExtensions.EnumParse<T>(value, false);
    }

    public static T EnumParse<T>(this string value, bool ignorecase) {

        if (value == null) {
            throw new ArgumentNullException("value");
        }

        value = value.Trim();

        if (value.Length == 0) {
            throw new ArgumentException("Must specify valid information for parsing in the string.", "value");
        }

        Type t = typeof(T);

        if (!t.IsEnum) {
            throw new ArgumentException("Type provided must be an Enum.", "T");
        }

        return (T)Enum.Parse(t, value, ignorecase);
    }
}

Útil para analizar una cadena en una enumeración.

public enum TestEnum
{
    Bar,
    Test
}

public class Test
{
    public void Test()
    {
        TestEnum foo = "Test".EnumParse<TestEnum>();
    }
 }

El crédito va a Scott Dorman

--- Editar para el proyecto Codeplex ---

Le pregunté a Scott Dorman si le importaría que publiquemos su código en el proyecto Codeplex. Esta es la respuesta que recibí de él:

Gracias por el aviso tanto en la publicación SO como en el proyecto CodePlex. He votado tu respuesta sobre la pregunta. Sí, el código está efectivamente en el dominio público actualmente bajo la Licencia abierta de CodeProject ( http://www.codeproject.com/info/cpol10.aspx ).

No tengo problemas con que esto se incluya en el proyecto CodePlex, y si desea agregarme al proyecto (el nombre de usuario es sdorman) agregaré ese método más algunos métodos auxiliares de enumeración adicionales.

revs mlarsen
fuente
Este escenario de análisis de enumeraciones aparece todo el tiempo ... tengo que poner esto en mi
biblioteca
Wow, he estado escribiendo métodos para asignar cadenas a enumeraciones (recién comencé a usar .NET). ¡Gracias, esto ayudará absolutamente!
Kevin
44
También puede considerar nombrar este ToEnum <> (), ya que viene después del objeto.
Neil
Tenga en cuenta que Enum. TryParse <T> se ha agregado a Net 4.0 - blogs.msdn.com/bclteam
Dan Diplo
1
No creo que este método deba usar Trim. Recortar la entrada debe ser responsabilidad de la persona que llama.
CodesInChaos
32

Este me parece bastante útil:

public static class PaulaBean
{
    private static String paula = "Brillant";
    public static String GetPaula<T>(this T obj) {
        return paula;
    }
}

Puede usarlo en CodePlex.

Julieta
fuente
2
¿Puede alguien ser tan amable de explicárselo a los menos dotados de nosotros?
jpbochi
jajaja Acabo de leer el artículo (el comentario de Joel arriba): es curioso, pero después de haber estado en el mismo bote (en el extremo receptor, no en el extremo de Paula) ¡es curioso mirar hacia atrás! Una vez que contrataron a un contratista para trabajar en un proyecto en el que fui diseñadora / devota líder, no estaba bajo mi control directo, pero se le asignó el trabajo de la lista de trabajo de mi equipo. Los jefes la elogiaron por ser brillante (¡incluso contratarla más tarde como Dev Lead!). ¡Nunca se les ocurrió que cada código que escribió o diseñó no había llegado a producción y mi equipo tuvo que reescribirlo completamente desde cero!
Wolf5370
31

DateTimeExtensions

Ejemplos:

DateTime firstDayOfMonth = DateTime.Now.First();
DateTime lastdayOfMonth = DateTime.Now.Last();
DateTime lastFridayInMonth = DateTime.Now.Last(DayOfWeek.Friday);
DateTime nextFriday = DateTime.Now.Next(DayOfWeek.Friday);
DateTime lunchTime = DateTime.Now.SetTime(11, 30);
DateTime noonOnFriday = DateTime.Now.Next(DayOfWeek.Friday).Noon();
DateTime secondMondayOfMonth = DateTime.Now.First(DayOfWeek.Monday).Next(DayOfWeek.Monday).Midnight();
CMS
fuente
55
Sugeriría cambiar el nombre de "SetTime" a "WithTime", ya que en realidad no lo establece en el valor existente. Agradable de lo contrario sin embargo.
Jon Skeet
28
DateTime.Now.First (): primero, ¿qué? Solo se desprende del código de muestra.
mackenir
2
Muy agradable. Pero acepte que los nombres podrían ser mucho mejores.
Bovium
DateTime.Now.First será lo suficientemente claro en Intellisense si el método está bien documentado.
Ryan Lundy
29

gitorious.org/cadenza es una biblioteca completa de algunos de los métodos de extensión más útiles que he visto.

sontek
fuente
12 métodos de extensión bastante básicos. Estoy un poco decepcionado por las mono-rocas.
mackenir
(Estoy hablando de la versión lanzada, no la que necesita usar el control de fuente para obtener)
mackenir
28

Aquí hay uno que uso con frecuencia para formatear presentaciones.

public static string ToTitleCase(this string mText)
{
    if (mText == null) return mText;

    System.Globalization.CultureInfo cultureInfo = System.Threading.Thread.CurrentThread.CurrentCulture;
    System.Globalization.TextInfo textInfo = cultureInfo.TextInfo;

    // TextInfo.ToTitleCase only operates on the string if is all lower case, otherwise it returns the string unchanged.
    return textInfo.ToTitleCase(mText.ToLower());
}
Venr
fuente
Whoah, el manejo de excepciones de Pokémon va a ocultar problemas como ThreadAbortException, etc. Por favor, detecte algo específico.
JBRWilkinson
28

Aquí hay una lista de números romanos. No se usa con frecuencia, pero podría ser útil. Uso:

if ("IV".IsValidRomanNumeral())
{
   // Do useful stuff with the number 4.
}

Console.WriteLine("MMMDCCCLXXXVIII".ParseRomanNumeral());
Console.WriteLine(3888.ToRomanNumeralString());

La fuente:

    public static class RomanNumeralExtensions
    {
        private const int NumberOfRomanNumeralMaps = 13;

        private static readonly Dictionary<string, int> romanNumerals =
            new Dictionary<string, int>(NumberOfRomanNumeralMaps)
            {
                { "M", 1000 }, 
                { "CM", 900 }, 
                { "D", 500 }, 
                { "CD", 400 }, 
                { "C", 100 }, 
                { "XC", 90 }, 
                { "L", 50 }, 
                { "XL", 40 }, 
                { "X", 10 }, 
                { "IX", 9 }, 
                { "V", 5 }, 
                { "IV", 4 }, 
                { "I", 1 }
            };

        private static readonly Regex validRomanNumeral = new Regex(
            "^(?i:(?=[MDCLXVI])((M{0,3})((C[DM])|(D?C{0,3}))"
            + "?((X[LC])|(L?XX{0,2})|L)?((I[VX])|(V?(II{0,2}))|V)?))$", 
            RegexOptions.Compiled);

        public static bool IsValidRomanNumeral(this string value)
        {
            return validRomanNumeral.IsMatch(value);
        }

        public static int ParseRomanNumeral(this string value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            value = value.ToUpperInvariant().Trim();

            var length = value.Length;

            if ((length == 0) || !value.IsValidRomanNumeral())
            {
                throw new ArgumentException("Empty or invalid Roman numeral string.", "value");
            }

            var total = 0;
            var i = length;

            while (i > 0)
            {
                var digit = romanNumerals[value[--i].ToString()];

                if (i > 0)
                {
                    var previousDigit = romanNumerals[value[i - 1].ToString()];

                    if (previousDigit < digit)
                    {
                        digit -= previousDigit;
                        i--;
                    }
                }

                total += digit;
            }

            return total;
        }

        public static string ToRomanNumeralString(this int value)
        {
            const int MinValue = 1;
            const int MaxValue = 3999;

            if ((value < MinValue) || (value > MaxValue))
            {
                throw new ArgumentOutOfRangeException("value", value, "Argument out of Roman numeral range.");
            }

            const int MaxRomanNumeralLength = 15;
            var sb = new StringBuilder(MaxRomanNumeralLength);

            foreach (var pair in romanNumerals)
            {
                while (value / pair.Value > 0)
                {
                    sb.Append(pair.Key);
                    value -= pair.Value;
                }
            }

            return sb.ToString();
        }
    }
Jesse C. Slicer
fuente
Eso me recuerda a la PEP Python 313, que era una broma de los inocentes para incluir literales número romano en Python: python.org/dev/peps/pep-0313
rial
25

Una forma conveniente de lidiar con los tamaños:

public static class Extensions {
    public static int K(this int value) {
        return value * 1024;
    }
    public static int M(this int value) {
        return value * 1024 * 1024;
    }
}

public class Program {
    public void Main() {
        WSHttpContextBinding serviceMultipleTokenBinding = new WSHttpContextBinding() {
            MaxBufferPoolSize = 2.M(), // instead of 2097152
            MaxReceivedMessageSize = 64.K(), // instead of 65536
        };
    }
}
Paolo Tedesco
fuente
En mi opinión, este es un estilo de codificación realmente pobre. En su lugar, se deben usar constantes, no lógica ofuscada.
xxbbcc
24

Para controles Winform:

/// <summary>
/// Returns whether the function is being executed during design time in Visual Studio.
/// </summary>
public static bool IsDesignTime(this Control control)
{
    if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
    {
        return true;
    }

    if (control.Site != null && control.Site.DesignMode)
    {
        return true;
    }

    var parent = control.Parent;
    while (parent != null)
    {
        if (parent.Site != null && parent.Site.DesignMode)
        {
            return true;
        }
        parent = parent.Parent;
    }
    return false;
}

/// <summary>
/// Sets the DropDownWidth to ensure that no item's text is cut off.
/// </summary>
public static void SetDropDownWidth(this ComboBox comboBox)
{
    var g = comboBox.CreateGraphics();
    var font = comboBox.Font;
    float maxWidth = 0;

    foreach (var item in comboBox.Items)
    {
        maxWidth = Math.Max(maxWidth, g.MeasureString(item.ToString(), font).Width);
    }

    if (comboBox.Items.Count > comboBox.MaxDropDownItems)
    {
        maxWidth += SystemInformation.VerticalScrollBarWidth;
    }

    comboBox.DropDownWidth = Math.Max(comboBox.Width, Convert.ToInt32(maxWidth));
}

Uso de IsDesignTime:

public class SomeForm : Form
{
    public SomeForm()
    {
        InitializeComponent();

        if (this.IsDesignTime())
        {
            return;
        }

        // Do something that makes the visual studio crash or hang if we're in design time,
        // but any other time executes just fine
    }
}

Uso de SetDropdownWidth:

ComboBox cbo = new ComboBox { Width = 50 };
cbo.Items.Add("Short");
cbo.Items.Add("A little longer");
cbo.Items.Add("Holy cow, this is a really, really long item. How in the world will it fit?");
cbo.SetDropDownWidth();

Olvidé mencionar, siéntase libre de usarlos en Codeplex ...

fre0n
fuente
1
Como se mencionó, esto es solo para WinForms. Puede funcionar con WPF pero hay problemas (descritos en el comentario sobre WPF en msdn.microsoft.com/en-us/library/… ). La mejor solución para WPF que he encontrado se describe en geekswithblogs.net/lbugnion/archive/2009/09/05/… (aunque, como es una propiedad estática, realmente no funciona como un método de extensión.)
scobi
23

ThrowIfArgumentIsNull es una buena manera de hacer esa verificación nula que todos deberíamos hacer.

public static class Extensions
{
    public static void ThrowIfArgumentIsNull<T>(this T obj, string parameterName) where T : class
    {
        if (obj == null) throw new ArgumentNullException(parameterName + " not allowed to be null");
    }
}

A continuación se muestra la forma de usarlo y funciona en todas las clases en su espacio de nombres o donde sea que use el espacio de nombres dentro.

internal class Test
{
    public Test(string input1)
    {
        input1.ThrowIfArgumentIsNull("input1");
    }
}

Está bien usar este código en el proyecto CodePlex .

bovium
fuente
Esto también me gusta, Jon lo tiene en el suyo, y yo uso algo similar de Umbrella, podría soportar soltar la parte "ArgumentIs".
cfeduke
¡Si! este es un método de extensión de kewl también :)
Pure.Krome
3
Si utiliza el constructor ArgumentNullException con solo 1 argumento de cadena, ese argumento debe ser solo el nombre del parámetro y no el mensaje de error. Por lo tanto, su código debería verse así: if (obj == null) arroje una nueva ArgumentNullException (parameterName);
Tommy Carlier el
Lo usaría default(T)para esto y eliminaría el requisito de clase.
Joel Coehoorn
1
@ Joel: los valores no predeterminados para los tipos nativos son argumentos legítimos con más frecuencia que los valores nulos. Verificar contra nulo tiene más sentido para mí que verificar contra el incumplimiento. Por supuesto, simplemente generalizo toda la idea diciendo Require.ThatArgument(input != null)o Require.ThatArgument(personId > 0). No requiere mucho más código, es mucho más flexible y se lee muy bien. Tengo anulaciones adicionales que toman funciones para cuando desea personalizar el mensaje de error o la excepción en sí.
StriplingWarrior
22

Echo de menos la instrucción With de Visual Basic cuando me muevo a C #, así que aquí va:

public static void With<T>(this T obj, Action<T> act) { act(obj); }

Y aquí está cómo usarlo en C #:

someVeryVeryLonggggVariableName.With(x => {
    x.Int = 123;
    x.Str = "Hello";
    x.Str2 = " World!";
});

¡Ahorra mucho tipeo!

Compare esto con:

someVeryVeryLonggggVariableName.Int = 123;
someVeryVeryLonggggVariableName.Str = "Hello";
someVeryVeryLonggggVariableName.Str2 = " World!";

poner en proyecto codeplex

chakrit
fuente
44
Solo una suposición, pero piense en lo que sucede si su T es una estructura.
Rauhotz el
55
También utilizo la sintaxis del inicializador de propiedades c # 3.0 siempre que sea posible para lograr el mismo resultado.
Steve el
3
@chakrit, aquí hay un ejemplo. Solo se aplica al crear el objeto Botón n = nuevo Botón {Nombre = "Botón1", Ancho = 100, Altura = 20, Activado = verdadero};
Steve
1
Esto sería útil para cuando tenga que conectar muchos eventos, porque la sintaxis del inicializador de propiedades de C # no admite eventos.
Gabe
1
esto también es útil fuera de los inicializadores de propiedades, porque solo puede usarlos al crear un nuevo objeto. Esta extensión puede funcionar en objetos creados previamente.
Brady Moritz
18

Toma un camelCaseWord o PascalCaseWord y lo "wordifica", es decir, camelCaseWord => camel Case Word

public static string Wordify( this string camelCaseWord )
{
    // if the word is all upper, just return it
    if( !Regex.IsMatch( camelCaseWord, "[a-z]" ) )
        return camelCaseWord;

    return string.Join( " ", Regex.Split( camelCaseWord, @"(?<!^)(?=[A-Z])" ) );
}

A menudo lo uso en conjunción con Capitalize

public static string Capitalize( this string word )
{
    return word[0].ToString( ).ToUpper( ) + word.Substring( 1 );
}

Ejemplo de uso

SomeEntityObject entity = DataAccessObject.GetSomeEntityObject( id );
List<PropertyInfo> properties = entity.GetType().GetPublicNonCollectionProperties( );

// wordify the property names to act as column headers for an html table or something
List<string> columns = properties.Select( p => p.Name.Capitalize( ).Wordify( ) ).ToList( );

De uso gratuito en proyecto codeplex

µBio
fuente
El Agregado en Capitalizar es bastante malo para el rendimiento, ya que crea muchas instancias de cadena. ¿Por qué no usar word.Substring (1) en su lugar?
Thomas Levesque
17

Encontré este útil

public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> pSeq)
{
    return pSeq ?? Enumerable.Empty<T>();
}

Elimina el cheque nulo en el código de llamada. Ahora puedes hacer

MyList.EmptyIfNull().Where(....)
Vasu Balakrishnan
fuente
Sí, si alguien olvidó el "Patrón de objetos nulos", este método es útil para parchearlo. La colección nunca debe ser nula.
Pavel Hodek
16

Convierte un doble a una cadena formateada usando la cultura especificada:

public static class ExtensionMethods 
{
  public static string ToCurrency(this double value, string cultureName)
  {
    CultureInfo currentCulture = new CultureInfo(cultureName);
    return (string.Format(currentCulture, "{0:C}", value));
  }
}

Ejemplo:

double test = 154.20;
string testString = test.ToCurrency("en-US"); // $154.20
CMS
fuente
13
Debería usar Decimal para la moneda, de lo contrario obtendrá problemas de redondeo
Andrew Bullock, el
¿Qué pasa con el uso de una enumeración en el parámetro en lugar de una cadena simple
Rulas
15

A continuación se muestra un método de extensión que adapta el código de Rick Strahl (y los comentarios también) para evitar que tenga que adivinar o leer la marca de orden de bytes de una matriz de bytes o un archivo de texto cada vez que lo convierte en una cadena.

El fragmento le permite simplemente hacer:

byte[] buffer = File.ReadAllBytes(@"C:\file.txt");
string content = buffer.GetString();

Si encuentra algún error, agréguelo a los comentarios. Siéntase libre de incluirlo en el proyecto Codeplex.

public static class Extensions
{
    /// <summary>
    /// Converts a byte array to a string, using its byte order mark to convert it to the right encoding.
    /// Original article: http://www.west-wind.com/WebLog/posts/197245.aspx
    /// </summary>
    /// <param name="buffer">An array of bytes to convert</param>
    /// <returns>The byte as a string.</returns>
    public static string GetString(this byte[] buffer)
    {
        if (buffer == null || buffer.Length == 0)
            return "";

        // Ansi as default
        Encoding encoding = Encoding.Default;       

        /*
            EF BB BF    UTF-8 
            FF FE UTF-16    little endian 
            FE FF UTF-16    big endian 
            FF FE 00 00 UTF-32, little endian 
            00 00 FE FF UTF-32, big-endian 
         */

        if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
            encoding = Encoding.UTF8;
        else if (buffer[0] == 0xfe && buffer[1] == 0xff)
            encoding = Encoding.Unicode;
        else if (buffer[0] == 0xfe && buffer[1] == 0xff)
            encoding = Encoding.BigEndianUnicode; // utf-16be
        else if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff)
            encoding = Encoding.UTF32;
        else if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76)
            encoding = Encoding.UTF7;

        using (MemoryStream stream = new MemoryStream())
        {
            stream.Write(buffer, 0, buffer.Length);
            stream.Seek(0, SeekOrigin.Begin);
            using (StreamReader reader = new StreamReader(stream, encoding))
            {
                return reader.ReadToEnd();
            }
        }
    }
}
Chris S
fuente
Método muy útil, pero no creo que deba ser un método de extensión.
Pop Catalin
Si estás escribiendo un editor de texto que probablemente garantiza un método de extensión, pero estoy de acuerdo la mayoría de las veces es probablemente no más de un método privado estática
Chris S
15

Aquí hay uno que acabo de crear hoy.

// requires .NET 4

public static TReturn NullOr<TIn, TReturn>(this TIn obj, Func<TIn, TReturn> func,
        TReturn elseValue = default(TReturn)) where TIn : class
    { return obj != null ? func(obj) : elseValue; }

// versions for CLR 2, which doesn't support optional params

public static TReturn NullOr<TIn, TReturn>(this TIn obj, Func<TIn, TReturn> func,
        TReturn elseValue) where TIn : class
    { return obj != null ? func(obj) : elseValue; }
public static TReturn NullOr<TIn, TReturn>(this TIn obj, Func<TIn, TReturn> func)
        where TIn : class
    { return obj != null ? func(obj) : default(TReturn); }

Te permite hacer esto:

var lname = thingy.NullOr(t => t.Name).NullOr(n => n.ToLower());

que es más fluido y (IMO) más fácil de leer que esto:

var lname = (thingy != null ? thingy.Name : null) != null
    ? thingy.Name.ToLower() : null;
Scott Bilas
fuente
1
¿Qué pasa si quiero thingy.NullOr(t => t.Count), dónde Countestá un int? Debería devolver en default(TReturn)lugar de nulo, de esa manera no necesitará la classrestricción y también funcionará para los tipos de valor
Thomas Levesque,
2
Se debe requerir que TIn sea una clase, de lo contrario, este método de extensión completo no tiene sentido (los tipos de valor no pueden ser nulos). Y su ejemplo con t.Count funciona con el método de extensión anterior. ¿Podrías echar un segundo vistazo?
scobi
@Scott: este es un método útil para un problema común. Sin embargo, ¿creo TReturn elseValue = default(TReturn)que solo está disponible para .NET 4.0? Tengo 3.5 SP1 y nunca he visto esa construcción (tampoco mi compilador). Acabo de mover esto al interior del método. Sin embargo, un problema es que al encajonar un tipo anulable a un objeto para usarlo con el método se obtiene un resultado inesperado (0 frente a nulo esperado).
Jim Schubert
@ Jim: la default(T)palabra clave ha estado allí desde VS2005, pero creo que los parámetros predeterminados son una nueva característica de .NET 4. La forma fácil de evitarlo debería ser tener dos variantes, una que tome el parámetro y otra que no. Actualizaré la respuesta para que sea compatible con CLR 2.0. En cuanto al boxeo, ese es el punto default. Serán datos 0 inicializados para un tipo de valor y nulos para todos los tipos de referencia. Un TReturn de un tipo de valor debe permanecer sin caja durante toda la función.
scobi
@Scott: Mi pregunta era sobre el parámetro predeterminado, que solo he visto en lenguajes dinámicos como Ruby. Mi punto con respecto a los tipos anulables es que el retorno x.Valuedebe devolver nulo (si, por ejemplo, int?era nulo) o el valor si int?tiene un valor. Volver 0cuando int? x = nullse pasa y se encajona al objeto es un caso extraño. He visto comprobaciones similares para tipos anulables en bibliotecas como nhibernate y linfu con fluidez (creo) para este caso específico, lo que le permite eliminar la restricción de clase como se sugirió anteriormente.
Jim Schubert
14

"Marque sus respuestas con la aceptación de incluir el código en el proyecto Codeplex".

¿Por qué? Todas las cosas en este sitio bajo CC-by-sa-2.5 , así que simplemente coloque su Proyecto de desbordamiento de extensión bajo la misma licencia y puede usarlo libremente.

De todos modos, aquí hay una función String.Reverse, basada en esta pregunta .

/// <summary>
/// Reverse a String
/// </summary>
/// <param name="input">The string to Reverse</param>
/// <returns>The reversed String</returns>
public static string Reverse(this string input)
{
    char[] array = input.ToCharArray();
    Array.Reverse(array);
    return new string(array);
}
Michael Stum
fuente
¿String ya no implementa IEnumerable <char>? Por lo tanto, solo tendría que devolver new String (input.Reverse ());
Iain Galloway
Una implementación usando StringBuilder debería ser más rápida.
CodesInChaos
1
@CodeInChaos La evaluación comparativa en stackoverflow.com/questions/228038 midió que StringBuilder es más lento.
Michael Stum
Tienes razón. Parece que los requisitos de seguridad de subprocesos (probablemente para garantizar la inmutabilidad de la cadena devuelta por ToString) ralentizan mucho StringBuilder.
CodesInChaos
2
Espero que no encuentres sustitutos o personajes combinados.
dalle
14

Me cansé de la tediosa verificación nula al extraer valores de MySqlDataReader, así que:

public static DateTime? GetNullableDateTime(this MySqlDataReader dr, string fieldName)
{
    DateTime? nullDate = null;
    return dr.IsDBNull(dr.GetOrdinal(fieldName)) ? nullDate : dr.GetDateTime(fieldName);
}

public static string GetNullableString(this MySqlDataReader dr, string fieldName)
{
    return dr.IsDBNull(dr.GetOrdinal(fieldName)) ? String.Empty : dr.GetString(fieldName);
}

public static char? GetNullableChar(this MySqlDataReader dr, string fieldName)
{
    char? nullChar = null;
    return dr.IsDBNull(dr.GetOrdinal(fieldName)) ? nullChar : dr.GetChar(fieldName);
}

Por supuesto, esto podría usarse con cualquier SqlDataReader.


Tanto Hangy como Joe tuvieron algunos buenos comentarios sobre cómo hacer esto, y desde entonces tuve la oportunidad de implementar algo similar en un contexto diferente, así que aquí hay otra versión:

public static int? GetNullableInt32(this IDataRecord dr, int ordinal)
{
    int? nullInt = null;
    return dr.IsDBNull(ordinal) ? nullInt : dr.GetInt32(ordinal);
}

public static int? GetNullableInt32(this IDataRecord dr, string fieldname)
{
    int ordinal = dr.GetOrdinal(fieldname);
    return dr.GetNullableInt32(ordinal);
}

public static bool? GetNullableBoolean(this IDataRecord dr, int ordinal)
{
    bool? nullBool = null;
    return dr.IsDBNull(ordinal) ? nullBool : dr.GetBoolean(ordinal);
}

public static bool? GetNullableBoolean(this IDataRecord dr, string fieldname)
{
    int ordinal = dr.GetOrdinal(fieldname);
    return dr.GetNullableBoolean(ordinal);
}
Adam Lassek
fuente
2
Esto también debería funcionar como un método de extensión para IDataReader.
Hangy
2
En realidad, cree el parámetro "this" de tipo IDataRecord para obtener la máxima compatibilidad. En mi versión de esto, tengo una sobrecarga que toma un ordinal, que llama la versión fieldName. Guarda el "GetOrdinal" seguido de una búsqueda por nombre.
Joel Mueller
Existe una implementación adecuada, que puede manejar cualquier tipo de valor: rabdullin.com/journal/2008/12/6/…
Rinat Abdullin
Gracias Rinat, en realidad lo he reducido a un único método genérico: consulte stackoverflow.com/questions/303287
Adam Lassek
Todos estos métodos parecen ser innecesarios ya que puede usar la aspalabra clave para obtener un valor de un lector que permita nulo. Si combina el ??operador de fusión nulo con el operador as, incluso puede tener un valor predeterminado no nulo para ir directamente a un tipo de valor. Ver stackoverflow.com/questions/746767/…
stevehipwell
14

Me irritó que LINQ me dé un OrderBy que toma una clase que implementa IComparer como argumento, pero no admite pasar una función de comparación anónima simple. Lo rectifiqué.

Esta clase crea un IComparer a partir de su función de comparación ...

/// <summary>
///     Creates an <see cref="IComparer{T}"/> instance for the given
///     delegate function.
/// </summary>
internal class ComparerFactory<T> : IComparer<T>
{
    public static IComparer<T> Create(Func<T, T, int> comparison)
    {
        return new ComparerFactory<T>(comparison);
    }

    private readonly Func<T, T, int> _comparison;

    private ComparerFactory(Func<T, T, int> comparison)
    {
        _comparison = comparison;
    }

    #region IComparer<T> Members

    public int Compare(T x, T y)
    {
        return _comparison(x, y);
    }

    #endregion
}

... y estos métodos de extensión exponen mis nuevas sobrecargas de OrderBy en enumerables. Dudo que esto funcione para LINQ to SQL, pero es genial para LINQ to Objects.

public static class EnumerableExtensions
{
    /// <summary>
    /// Sorts the elements of a sequence in ascending order by using a specified comparison delegate.
    /// </summary>
    public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
                                                                     Func<TKey, TKey, int> comparison)
    {
        var comparer = ComparerFactory<TKey>.Create(comparison);
        return source.OrderBy(keySelector, comparer);
    }

    /// <summary>
    /// Sorts the elements of a sequence in descending order by using a specified comparison delegate.
    /// </summary>
    public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
                                                                               Func<TKey, TKey, int> comparison)
    {
        var comparer = ComparerFactory<TKey>.Create(comparison);
        return source.OrderByDescending(keySelector, comparer);
    }
}

Puede poner esto en codeplex si lo desea.

Joel Mueller
fuente
13

Este es para MVC, agrega la capacidad de generar una <label />etiqueta a la Htmlvariable que está disponible en todos ViewPage. Esperemos que sea útil para otros que intentan desarrollar extensiones similares.

Utilizar:

<%= Html.Label("LabelId", "ForId", "Text")%>

Salida:

<label id="LabelId" for="ForId">Text</label>

Código:

public static class HtmlHelperExtensions
{
    public static string Label(this HtmlHelper Html, string @for, string text)
    {
        return Html.Label(null, @for, text);
    }

    public static string Label(this HtmlHelper Html, string @for, string text, object htmlAttributes)
    {
        return Html.Label(null, @for, text, htmlAttributes);
    }

    public static string Label(this HtmlHelper Html, string @for, string text, IDictionary<string, object> htmlAttributes)
    {
        return Html.Label(null, @for, text, htmlAttributes);
    }

    public static string Label(this HtmlHelper Html, string id, string @for, string text)
    {
        return Html.Label(id, @for, text, null);
    }

    public static string Label(this HtmlHelper Html, string id, string @for, string text, object htmlAttributes)
    {
        return Html.Label(id, @for, text, new RouteValueDictionary(htmlAttributes));
    }

    public static string Label(this HtmlHelper Html, string id, string @for, string text, IDictionary<string, object> htmlAttributes)
    {
        TagBuilder tag = new TagBuilder("label");

        tag.MergeAttributes(htmlAttributes);

        if (!string.IsNullOrEmpty(id))
            tag.MergeAttribute("id", Html.AttributeEncode(id));

        tag.MergeAttribute("for", Html.AttributeEncode(@for));

        tag.SetInnerText(Html.Encode(text));

        return tag.ToString(TagRenderMode.Normal);
    }
}
2 revoluciones16
fuente
Echa un vistazo a MvcContrib.FluentHtml
Arnis Lapsa el
Esto probablemente debería duplicarse con Literal en su lugar.
Mark Hurd
12

Convertir esto:

DbCommand command = connection.CreateCommand();
command.CommandText = "SELECT @param";

DbParameter param = command.CreateParameter();
param.ParameterName = "@param";
param.Value = "Hello World";

command.Parameters.Add(param);

... dentro de esto:

DbCommand command = connection.CreateCommand("SELECT {0}", "Hello World");

... usando este método de extensión:

using System;
using System.Data.Common;
using System.Globalization;
using System.Reflection;

namespace DbExtensions {

   public static class Db {

      static readonly Func<DbConnection, DbProviderFactory> getDbProviderFactory;
      static readonly Func<DbCommandBuilder, int, string> getParameterName;
      static readonly Func<DbCommandBuilder, int, string> getParameterPlaceholder;

      static Db() {

         getDbProviderFactory = (Func<DbConnection, DbProviderFactory>)Delegate.CreateDelegate(typeof(Func<DbConnection, DbProviderFactory>), typeof(DbConnection).GetProperty("DbProviderFactory", BindingFlags.Instance | BindingFlags.NonPublic).GetGetMethod(true));
         getParameterName = (Func<DbCommandBuilder, int, string>)Delegate.CreateDelegate(typeof(Func<DbCommandBuilder, int, string>), typeof(DbCommandBuilder).GetMethod("GetParameterName", BindingFlags.Instance | BindingFlags.NonPublic, Type.DefaultBinder, new Type[] { typeof(Int32) }, null));
         getParameterPlaceholder = (Func<DbCommandBuilder, int, string>)Delegate.CreateDelegate(typeof(Func<DbCommandBuilder, int, string>), typeof(DbCommandBuilder).GetMethod("GetParameterPlaceholder", BindingFlags.Instance | BindingFlags.NonPublic, Type.DefaultBinder, new Type[] { typeof(Int32) }, null));
      }

      public static DbProviderFactory GetProviderFactory(this DbConnection connection) {
         return getDbProviderFactory(connection);
      }

      public static DbCommand CreateCommand(this DbConnection connection, string commandText, params object[] parameters) {

         if (connection == null) throw new ArgumentNullException("connection");

         return CreateCommandImpl(GetProviderFactory(connection).CreateCommandBuilder(), connection.CreateCommand(), commandText, parameters);
      }

      private static DbCommand CreateCommandImpl(DbCommandBuilder commandBuilder, DbCommand command, string commandText, params object[] parameters) {

         if (commandBuilder == null) throw new ArgumentNullException("commandBuilder");
         if (command == null) throw new ArgumentNullException("command");
         if (commandText == null) throw new ArgumentNullException("commandText");

         if (parameters == null || parameters.Length == 0) {
            command.CommandText = commandText;
            return command;
         }

         object[] paramPlaceholders = new object[parameters.Length];

         for (int i = 0; i < paramPlaceholders.Length; i++) {

            DbParameter dbParam = command.CreateParameter();
            dbParam.ParameterName = getParameterName(commandBuilder, i);
            dbParam.Value = parameters[i] ?? DBNull.Value;
            command.Parameters.Add(dbParam);

            paramPlaceholders[i] = getParameterPlaceholder(commandBuilder, i);
         }

         command.CommandText = String.Format(CultureInfo.InvariantCulture, commandText, paramPlaceholders);

         return command;
      }
   }
}

Más métodos de extensión ADO.NET: DbExtensions

Max Toro
fuente