Quali sono i tuoi metodi di estensione preferiti per C #? (Codeplex.com/extensionoverflow)


478

Facciamo un elenco di risposte in cui pubblichi i tuoi metodi di estensione eccellenti e preferiti .

Il requisito è che sia necessario pubblicare il codice completo e un esempio e una spiegazione su come utilizzarlo.

Sulla base del grande interesse per questo argomento, ho impostato un progetto Open Source chiamato extensionoverflow su Codeplex .

Contrassegna le risposte con un'accettazione per inserire il codice nel progetto Codeplex.

Si prega di pubblicare il codice sorgente completo e non un collegamento.

Notizie Codeplex:

24.08.2010 La pagina Codeplex è ora qui: http://extensionoverflow.codeplex.com/

11.11.2008 XmlSerialize / XmlDeserialize è ora implementato e testato sull'unità .

11.11.2008 C'è ancora spazio per più sviluppatori. ;-) Iscriviti ADESSO!

11.11.2008 Il terzo collaboratore si è unito a ExtensionOverflow , benvenuto in BKristensen

11.11.2008 FormatWith è ora implementato e unit testato .

09.11.2008 Il secondo collaboratore si è unito a ExtensionOverflow . benvenuto in chakrit .

09.11.2008 Abbiamo bisogno di più sviluppatori. ;-)

09.11.2008 ThrowIfArgumentIsNull in Now Implemented e Unit Tested on Codeplex.


Ora il primo codice è dedicato al sito Codeplex.
bovium

Erik purtroppo tutto è iniziato ora su codeplex. Per favore, unisciti comunque.
bovium,

3
Sembra abbastanza buono Ho un commento sulla denominazione delle classi statiche. Denominarli <type> Extensions non è molto informativo. Ad esempio StringExtensions contiene sia elementi di formattazione che xml. Penso che sia meglio nominare la classe con il motivo per cui stai estendendo quel tipo. Ad esempio UnixDateTimeConversions. Puoi ragionevolmente indovinare che contiene metodi per la conversione da e verso Unix time. Solo un pensiero!
ecoffey,

Controlla questo URL per ulteriori informazioni sui metodi di estensione C # planetofcoders.com/c-extension-methods
Gaurav Agrawal

Risposte:


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

Mi permette di sostituire:

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....
}

2
Bene si compila se si utilizza System.Linq;
Ryu,

11
Forse "EqualsAnyOf" sarebbe un nome migliore di "In"?
Tom Bushell,

10
Non sono sicuro che mi piaccia - mi piace la brevità di In, ma forse IsInsarebbe meglio.
Winston Smith,

50
Usando lo stesso metodo Contains: (new [] {1, 2, 3}). Contiene (a)
Max Toro

4
Ho pensato In<T>(...)anche a questo e ho trovato il metodo di estensione più utile al di fuori della libreria standard. Ma sono in contrasto con il nome In. Un nome di metodo dovrebbe descrivere ciò che fa, ma Innon lo fa. L'ho chiamato IsAnyOf<T>(...), ma credo che IsIn<T>(...)sarebbe adeguato.
JBSnorro,

160

Ho vari metodi di estensione nel mio progetto MiscUtil (la fonte completa è disponibile lì - non lo ripeterò qui). I miei preferiti, alcuni dei quali coinvolgono altre classi (come intervalli):

Data e ora - principalmente per test unitari. Non sono sicuro che li userei in produzione :)

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

Range e stepping: un enorme ringraziamento a Marc Gravell per il suo personale operatore per renderlo possibile:

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

confronti:

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

Verifica argomento:

x.ThrowIfNull("x");

LINQ to XML applicato a tipi anonimi (o altri tipi con proprietà appropriate):

// <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()

Push LINQ - impiegherebbe troppo tempo a spiegare qui, ma cercalo.


1
Bello! Dovresti metterlo su Google Code o CodePlex in modo che io possa inviarti alcune patch :-) Prometto che sarà leggibile :-P
chakrit

3
@bovium: puoi già vedere il codice. Segui il link nella prima frase: c'è la fonte completa.
Jon Skeet,

1
@bovium: Preferirei farlo da solo, inserendolo su code.google.com e gestendo il progetto da solo, se non ti dispiace. Ovviamente sei in possesso della licenza per metterlo su Codeplex se mantieni l'attribuzione appropriata, ma preferirei risolverlo da solo a meno che tu non sia disperato :)
Jon Skeet

1
@Jon Skeet. È messo sotto licenza MIT gratuitamente per tutti. Commercialmente o open source. Perché non unire le forze e creare una libreria di metodi di estensione per il pubblico.
bovium

1
Solo perché faccio molti altri frammenti in quella libreria. Sei il benvenuto a prenderne una copia per il tuo progetto, ma preferirei conservarne una copia anche nel mio progetto.
Jon Skeet,

147

string.Format scorciatoia:

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

Esempio:

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

Per un rapido copia e incolla vai qui .

Non trovi più naturale digitare "some string".F("param")invece di string.Format("some string", "param")?

Per un nome più leggibile , prova uno di questi suggerimenti:

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

..


11
È certamente breve, ma sarà illeggibile per tutti i nuovi membri della tua squadra.
Jon Skeet,

3
Penso che la leggibilità sia più importante nello schema più ampio del tuo codice rispetto a poche dichiarazioni stenografiche che potrebbero essere rapidamente consultate / chieste.
chakrit,

6
Personalmente vorrei un oggetto Formatter separato, che il BCL potrebbe analizzare il modello di una volta e riutilizzare. Ciò aumenterebbe la leggibilità e le prestazioni. Ho chiesto al team BCL - vedremo ...
Jon Skeet il

3
È un metodo di estensione, ovviamente sarà illeggibile per i nuovi membri del team. Ho pensato che fosse l'idea con questa roba spiritosa? In quale altro modo i nuovi membri sapranno quanto siamo intelligenti?
MarkJ,

17
Ok ... Sono appena andato a metterlo in azione e sono andato con. Con - così ottieni "Questo è un {0}". Con ("test") ed è molto leggibile e ha senso. FYI
klkitchens

89

Sono utili?

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!");

questo imita la funzione random.choice (seq) di Pythons. simpatico.
Daren Thomas,

6
Cose di coppia: consiglierei di OneOfaccettarne una qualsiasi IList<T> . Quindi potresti sempre avere anche un sovraccarico che prende un paramsarg e lo passa semplicemente nel IList<T>sovraccarico. Ho dato una risposta (in basso in questo momento) con un NextBoolmetodo simile al tuo CoinToss, ma con un sovraccarico che accetta un probabilityparametro (e se volessi che qualcosa accadesse il 75% delle volte?). Inoltre, basta un pignolo: il tuo codice di esempio genererà un NullReferenceExceptiondato poiché randnon viene mai inizializzato.
Dan Tao,

3
+1 Mi piace molto, ma preferisco CoinTossimplementarlo rng.NextDouble() < .5perché internamente .Next(int)è realizzato in .NextDouble()modo da salvare un cast, un * e un segno di spunta.
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;
  }
}

Esempio:

if (myNumber.Between(3,7))
{
  // ....
}

19
Adoro questo, ma sto cercando di decidere se è giusto fare in modo che i limiti vengano controllati inclusivamente sul valore minimo ma esclusivo sul valore massimo. Mi chiedo se sarebbe confuso. 5.Tra (5,10) è vera ma 5.Tra (1,5) è falsa. Non sono nemmeno sicuro che un metodo Compagno all'interno sarebbe di aiuto. Thougts?
Steve Hiner,

12
Il nome "IsB Between" non avrebbe più senso? Forse anche fare un IsBetweenInclusive e IsBetweenExclusive. Non ho idea di quale prendere per impostazione predefinita.
fretje,

2
@Steve: ha più senso se fosse un'estensione datetime.
Joel Coehoorn,

16
Per me tra implica: 5. Tra (5,10) restituisce false, e 10. Tra (5,10) restituisce anche false. Mi sembra naturale.
Alex Baranosky,

3
Mi sembra che più persone abbiano idee diverse su ciò che è naturale. Per questo motivo, probabilmente dovrebbe essere esplicitamente dichiarato ciò che viene utilizzato (vale a dire Inclusive vs Exclusive), poiché potrebbe essere una fonte di errori molto semplice.
David Miani,

58

Il metodo di estensione:

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

Il metodo si applica a tutti i tipi e consente di aggiungere un intervallo di elementi a un elenco come parametri.

Esempio:

var list = new List<Int32>();
list.AddRange(5, 4, 8, 4, 2);

15
Sarebbe meglio come questo IList <T>

21
Usa solo l'inizializzatore di raccolta =>var list = new List<int>{5,4,8,4,2};
Arnis Lapsa il

Perché non solo chiamare List <T> .AddRange (raccolta IEnumerable <T>) nel tuo metodo?
Rauhotz,

8
@Will: In realtà, sarebbe meglio accettare un ICollection<T>; quindi potrebbe anche essere utilizzato, ad esempio, LinkedList<T>e HashSet<T>non solo su raccolte indicizzate.
Dan Tao,

2
Modificato per consentire la covarianza in pre.net 4.0
BlueRaja - Danny Pflughoeft

55

Inseriscilo sicuramente nel progetto codeplex.

Serializzazione / deserializzazione di oggetti in 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.
    }
}

8
Sarei tentato di chiamare il primo ToXml()(come ToString())
Jay Bazuzi il

1
Mi scuso con l'OP se lo ha scritto intenzionalmente in questo modo, ma l'uso di MemoryStreams AND XmlReader / XmlWriter è stato eccessivo. La classe StringReader e StringWriter sono perfette per questa operazione.
Portman,

2
Attenzione, questo non è sicuro per i thread. Devi assolutamente sincronizzare l'accesso al dizionario dei serializzatori statici.
Yann Schwartz,

2
@Yann, @T, È molto più semplice se aggiungi semplicemente l'attributo "thread static". Quindi verrà creata una nuova cache per thread. Non è necessaria la sincronizzazione.
Frank Krueger,

1
@Jonathan C Dickinson: sembra dai documenti MSDN qui msdn.microsoft.com/en-us/library/… che il costruttore utilizzato (nuovo XmlSerializer (tipo)) non presenta un problema di perdita di memoria. Quindi forse il codice di cache non è necessario?
slolife,

46

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

Esempio ingenuo:

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

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

Fantastico esempio:

// 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:

Questo non è come Selectperché si Select aspetta che la tua funzione restituisca qualcosa per trasformarsi in un altro elenco.

ForEach ti consente semplicemente di eseguire qualcosa per ciascuno degli elementi senza alcuna trasformazione / manipolazione dei dati.

Ho fatto questo in modo da poter programmare in uno stile più funzionale e sono rimasto sorpreso dal fatto che List abbia un ForEach mentre IEnumerable no.

Inseriscilo nel progetto codeplex


13
Pubblica il motivo per cui le estensioni IEnumerable <T> di LINQ non includono ForEach: stackoverflow.com/questions/317874/…
Neil,

13
Consiglio di leggere questo prima di usare il metodo: blogs.msdn.com/ericlippert/archive/2009/05/18/…
jpbochi

2
@jpbochi: questa è solo una demagogia di Microsoft
abatishchev,

1
@abatishchev E il tuo commento è solo un pregiudizio contro Microsoft. Non invalida alcuna parola scritta da Eric. Gli argomenti di qualcuno non vengono resi validi o non validi solo a causa della società per cui lavora.
jpbochi,

1
A proposito, vorrei chiarire un punto. Non ho detto che non dovresti usare questo metodo di estensione ForEach. Ho appena detto che dovresti considerare i punti esposti da Eric prima di decidere se usarlo o meno. L'ho letto e ho deciso di non usarlo. Sei libero di fare quello che vuoi con il tuo codice.
jpbochi,

43

Le mie estensioni di conversione che ti consentono di fare:

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

Eccolo, come pubblicato su 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;
    }
}

È possibile richiedere il valore predefinito (chiama il costruttore vuoto o "0" per i numeri) in caso di errore, specificare un valore "predefinito" (lo chiamo "altro") o chiedere null (dove T: class). Ho anche fornito entrambi i modelli di eccezione silenziosa e un tipico modello TryParse che restituisce un valore booleano che indica l'azione intrapresa e un parametro out contiene il nuovo valore. Quindi il nostro codice può fare cose come questa

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

Non sono riuscito a far sì che i tipi Nullable arrivassero al tutto in modo molto pulito. Ho provato per circa 20 minuti prima di gettare la spugna.


64
Personalmente, non sono un fan del codice che prova a catturare per determinare il risultato. Try / catch dovrebbe essere usato per errori che si verificano al di fuori della logica prevista, IMO. hmmmmm
Pure.Krome

Se non volessi che tu usassi il codice, non l'avrei pubblicato! :)
TheSoftwareJedi

Finalmente qualcosa di invisibile. Mi piace. :)
Arnis Lapsa,

8
Dovresti almeno cambiare quella clausola "catch" per catturare solo le eccezioni che ChangeType () solleverà quando non può "convertire" il riferimento. Penso che non vorresti avere OutOfMemoryException, ExecutionEngineException, ThreadAbortException o simili trattati come un errore di conversione. In caso contrario, sarà piuttosto difficile tenere traccia degli errori.
Christian.K,

2
Credo che ToOrNullabbia lo stesso identico comportamento ToOrDefault(ad esempio, se si chiama ToOrDefaultun tipo di riferimento con una conversione non riuscita, verrà restituito null). Ma ancora più importante, mi sembra ridondante dal momento che var s = myObject as stringrealizza la stessa cosa di var s = myObject.ToOrNull<string>()- ma senza dover potenzialmente prendere un InvalidCastException. Mi sto perdendo qualcosa?
Dan Tao,

43

Ho un metodo di estensione per la registrazione delle eccezioni:

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

Ed è usato in questo modo:

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

[scusa per aver pubblicato due volte; il secondo è meglio progettato :-)]


2
Dovresti leggere il registro vuoto statico pubblico (questa eccezione obj) {} forse?
Chris S,

Penso che questo vada bene per le eccezioni BCL o di terze parti, ma se esegui il rollback dei tuoi tipi di eccezione, puoi inserire la registrazione nella classe di eccezioni di base. In questo modo non devi ricordarti di chiamare 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);
    }
}

Utile per analizzare una stringa in un Enum.

public enum TestEnum
{
    Bar,
    Test
}

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

Il merito va a Scott Dorman

--- Modifica per il progetto Codeplex ---

Ho chiesto a Scott Dorman se gli dispiacerebbe pubblicare il suo codice nel progetto Codeplex. Questa è la risposta che ho ricevuto da lui:

Grazie per l'heads-up sia sul post SO che sul progetto CodePlex. Ho votato a fondo la tua risposta alla domanda. Sì, il codice è effettivamente di dominio pubblico attualmente con licenza Open CodeProject ( http://www.codeproject.com/info/cpol10.aspx ).

Non ho problemi con questo essere incluso nel progetto CodePlex e se vuoi aggiungermi al progetto (username è sdorman) aggiungerò quel metodo più alcuni metodi di supporto enum aggiuntivi.


Questo scenario di analisi enummatica si presenta continuamente ... devo metterlo nella mia lib :-)
chakrit

Wow, ho scritto dei metodi per mappare le stringhe agli enum (ho appena iniziato a usare .NET). Grazie, questo sarà di grande aiuto!
Kevin,

4
Puoi anche prendere in considerazione la denominazione di ToEnum <> (), poiché viene dopo l'oggetto.
Neil,

Si noti che Enum. TryParse <T> è stato aggiunto a Net 4.0 - blogs.msdn.com/bclteam
Dan Diplo

1
Non credo che questo metodo dovrebbe usare Trim. Il taglio dell'input dovrebbe essere responsabilità del chiamante.
CodesInChaos,

32

Trovo questo abbastanza utile:

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

Puoi usarlo su CodePlex.


2
Qualcuno può essere così gentile da spiegarlo ai meno dotati di noi?
jpbochi,

hahaha Hai appena letto l'articolo (il commento di Joel sopra) - divertente vero, ma essendo stato praticamente nella stessa barca (alla fine della ricezione, non alla fine di Paula) è solo divertente guardare indietro! Una volta un appaltatore è stato portato a lavorare su un progetto in cui ero designigner / lead dev - non era sotto il mio controllo diretto, ma le è stato assegnato un lavoro dall'elenco di lavoro dei miei team. I boss l'hanno lodata come brillante (anche assumendola più tardi come Dev Dev!). Non è mai venuto in mente che ogni pezzo di codice che ha scritto o disegnato non era arrivato alla produzione e che il mio team ha dovuto riscrivere completamente da zero!
Wolf5370,

31

DateTimeExtensions

Esempi:

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

5
Suggerirei di rinominare "SetTime" in "WithTime" poiché in realtà non lo sta impostando nel valore esistente. Bello altrimenti però.
Jon Skeet,

28
DateTime.Now.First () - prima cosa? È evidente solo dal codice di esempio.
mackenir,

2
Molto bella. Ma d'accordo sul fatto che i nomi potrebbero essere molto migliori.
bovium

DateTime.Now.First sarà abbastanza chiaro in Intellisense se il metodo è ben documentato.
Ryan Lundy,

29

gitorious.org/cadenza è una libreria completa di alcuni dei metodi di estensione più utili che abbia mai visto.


12 metodi di estensione abbastanza semplici. Sono un po 'deludente dai monosassi.
mackenir,

(Sto parlando della versione rilasciata, non quella che è necessario utilizzare il controllo del codice sorgente per ottenere)
mackenir

28

Eccone uno che uso frequentemente per la formattazione della presentazione.

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

Whoah, la gestione delle eccezioni di Pokemon nasconderà problemi come ThreadAbortException, ecc. Ti preghiamo di prendere qualcosa di specifico.
JBR Wilkinson,

28

Ecco un da e per numeri romani. Non usato spesso, ma potrebbe essere utile. Uso:

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

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

La fonte:

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

Questo mi ricorda il Python PEP 313, che era uno scherzo April Fools includere letterali in numeri romani in pitone: python.org/dev/peps/pep-0313
torial

25

Un modo conveniente per gestire le taglie:

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

Secondo me questo è davvero uno stile di programmazione davvero scadente. Costanti dovrebbero essere usate invece, non logica offuscata.
xxbbcc,

24

Per i controlli 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));
}

Utilizzo di 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
    }
}

SetDropdownWidth Utilizzo:

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

Ho dimenticato di menzionare, sentiti libero di usarli su Codeplex ...


1
Come accennato, questo è solo per WinForms. Potrebbe funzionare con WPF ma ci sono problemi (descritti nel commento su WPF su msdn.microsoft.com/en-us/library/… ). La migliore soluzione per WPF che ho trovato è descritta in geekswithblogs.net/lbugnion/archive/2009/09/05/… (sebbene sia una proprietà statica, non funziona davvero come metodo di estensione)
scobi

23

ThrowIfArgumentIsNull è un bel modo per fare quel controllo nullo che tutti dovremmo fare.

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

Di seguito è riportato il modo di usarlo e funziona su tutte le classi nel tuo spazio dei nomi o ovunque tu usi lo spazio dei nomi al suo interno.

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

Va bene usare questo codice sul progetto CodePlex .


Mi piace anche questo, Jon ce l'ha nel suo, e uso qualcosa di simile a Umbrella, potrebbe sopportare di abbandonare la parte "ArgumentIs".
cfeduke,

Si! anche questo è un metodo di estensione kewl :)
Pure.Krome

3
Se si utilizza ArgumentNullException-constructor con solo 1 argomento stringa, tale argomento deve essere solo il nome del parametro e non il messaggio di errore. Quindi il tuo codice dovrebbe apparire così: if (obj == null) lancia new ArgumentNullException (parameterName);
Tommy Carlier,

Userei default(T)per questo e rimuoverei il requisito di classe.
Joel Coehoorn,

1
@Joel: i valori non predefiniti per i tipi nativi sono argomenti legittimi più spesso dei valori null. Il controllo su null ha più senso per me rispetto al controllo su default. Certo, ho solo generalizzato l'intera idea dicendo Require.ThatArgument(input != null)o Require.ThatArgument(personId > 0). Non richiede molto più codice, è molto più flessibile e legge bene. Ho delle sostituzioni aggiuntive che richiedono funzioni per quando si desidera personalizzare il messaggio di errore o l'eccezione stessa.
StriplingWarrior il

22

Mi manca l' istruzione With di Visual Basic quando mi sposto in C #, quindi eccolo qui:

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

Ed ecco come usarlo in C #:

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

Risparmia molto digitando!

Confronta questo con:

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

mettere in progetto codeplex


4
Solo un'ipotesi, ma pensa a cosa succede se la tua T è una struttura.
Rauhotz,

5
Uso anche la sintassi dell'inizializzatore della proprietà c # 3.0 ove possibile per ottenere lo stesso risultato.
Steve,

3
@chakrit, ecco un esempio. Si applica solo quando si crea l'oggetto Button n = new Button {Name = "Button1", Width = 100, Height = 20, Enabled = true};
Steve,

1
Ciò sarebbe utile quando hai molti eventi da collegare, perché la sintassi dell'inizializzatore delle proprietà di C # non supporta gli eventi.
Gabe,

1
questo è anche utile al di fuori degli inizializzatori di proprietà, poiché è possibile utilizzarli solo quando si crea un nuovo oggetto. questa estensione può funzionare su oggetti precedentemente creati.
Brady Moritz,

18

Prende un camelCaseWord o PascalCaseWord e lo "identifica", cioè 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])" ) );
}

Lo uso spesso in combinazione con Capitalize

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

Esempio di utilizzo

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

Gratuito da usare nel progetto codeplex


L'aggregato in maiuscolo è piuttosto negativo per le prestazioni, perché crea molte istanze di stringa. Perché non usare word.Substring (1) invece?
Thomas Levesque,

17

Ho trovato questo utile

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

Rimuove il controllo null nel codice chiamante. Adesso potresti farlo

MyList.EmptyIfNull().Where(....)

Sì, se qualcuno ha dimenticato "Null Object Pattern" questo metodo è utile per correggerlo. La raccolta non dovrebbe mai essere nulla.
Pavel Hodek,

16

Converti un doppio in una stringa formattata usando la cultura specificata:

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

Esempio:

double test = 154.20;
string testString = test.ToCurrency("en-US"); // $154.20

13
Dovresti usare il decimale per la valuta, altrimenti otterrai problemi di arrotondamento
Andrew Bullock,

Che ne dici di usare un Enum nel parametro invece della semplice stringa
Rulas

15

Di seguito è riportato un metodo di estensione che adatta il codice di Rick Strahl (e anche i commenti) per evitare di dover indovinare o leggere il segno dell'ordine dei byte di un array di byte o di un file di testo ogni volta che lo si converte in una stringa.

Lo snippet ti consente di fare semplicemente:

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

Se trovi qualche bug, per favore aggiungi ai commenti. Sentiti libero di includerlo nel progetto 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();
            }
        }
    }
}

Metodo molto utile, ma non credo che dovrebbe essere e metodo di estensione.
Pop Catalin,

Se stai scrivendo un editor di testo probabilmente garantisce un metodo di estensione, ma concordo che la maggior parte delle volte probabilmente non è altro che un metodo privato statico
Chris S

15

Eccone uno che ho appena creato oggi.

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

Ti permette di fare questo:

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

che è più fluente e (IMO) più facile da leggere di questo:

var lname = (thingy != null ? thingy.Name : null) != null
    ? thingy.Name.ToLower() : null;

1
E se volessi thingy.NullOr(t => t.Count), dov'è Countun int? Dovresti restituire default(TReturn)piuttosto che null, in questo modo non avrai bisogno del classvincolo e funzionerà anche per tipi di valore
Thomas Levesque,

2
Dovrebbe essere richiesto che TIn sia una classe, altrimenti questo intero metodo di estensione non ha senso (i tipi di valore non possono essere nulli). E il tuo esempio con t.Count funziona con il metodo di estensione sopra. Potresti dare una seconda occhiata?
scobi,

@Scott: questo è un metodo utile per un problema comune. Tuttavia, credo TReturn elseValue = default(TReturn)sia disponibile solo per .NET 4.0? Ho 3.5 SP1 e non ho mai visto quel costrutto (né il mio compilatore). Ho appena spostato questo all'interno del metodo. Un problema, tuttavia, è che la boxe di un tipo nullable da obiettare per l'uso con il metodo produce un risultato imprevisto (0 vs null atteso).
Jim Schubert,

@Jim: la default(T)parola chiave esiste da VS2005, ma penso che i parametri predefiniti siano una nuova funzionalità di .NET 4. Il modo più semplice per aggirarlo dovrebbe essere avere due varianti, una che accetta il parametro e una che non lo fa. Aggiornerò la risposta per essere compatibile con CLR 2.0. Per quanto riguarda la boxe - questo è il punto default. Saranno dati 0 inizializzati per un tipo di valore e null per tutti i tipi di riferimento. Una restituzione di un tipo di valore deve rimanere senza box durante la funzione.
scobi,

@Scott: la mia domanda riguardava il parametro predefinito, che ho visto solo in linguaggi dinamici come Ruby. Il mio punto riguardo ai tipi nullable è che il ritorno x.Valuedovrebbe restituire null (se, per esempio, int?era null) o il valore se int?ha un valore. Restituire 0quando int? x = nullviene passato e inscatolato nell'oggetto è un caso strano. Ho visto controlli simili per tipi nullable in librerie come fluente nhibernate e linfu (credo) per questo caso specifico, che consente di eliminare il vincolo di classe come suggerito in precedenza.
Jim Schubert,

14

"Contrassegna le tue risposte con un'accettazione per inserire il codice nel progetto Codeplex."

Perché? Tutte le cose su questo sito sotto CC-by-sa-2.5 , quindi basta mettere il tuo progetto di overflow di estensione sotto la stessa licenza e puoi usarlo liberamente.

Comunque, ecco una funzione String.Reverse, basata su questa domanda .

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

String non implementa già IEnumerable <char>? Quindi avresti solo bisogno di restituire la nuova stringa (input.Reverse ());
Iain Galloway,

Un'implementazione che utilizza StringBuilder dovrebbe essere più veloce.
CodesInChaos,

1
@CodeInChaos Benchmarking in stackoverflow.com/questions/228038 misurata che StringBuilder è più lento.
Michael Stum

Hai ragione. Sembra che i requisiti di sicurezza del thread (probabilmente per garantire l'immutabilità della stringa restituita da ToString) rallentino molto StringBuilder.
CodesInChaos,

2
Spero di non incontrare surrogati o combinare personaggi.
dalle

14

Mi sono stancato del noioso controllo null mentre estraevo i valori da MySqlDataReader, quindi:

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

Naturalmente questo potrebbe essere usato con qualsiasi SqlDataReader.


Sia hangy che Joe hanno avuto dei buoni commenti su come farlo, e da allora ho avuto l'opportunità di implementare qualcosa di simile in un contesto diverso, quindi eccone un'altra versione:

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

2
Questo dovrebbe funzionare anche come metodo di estensione per IDataReader.
hangy

2
In realtà, rendere il parametro "this" di tipo IDataRecord per la massima compatibilità. Nella mia versione di questo, ho un sovraccarico che prende un ordinale, che la versione fieldName chiama. Salva "GetOrdinal" seguito da una ricerca per nome.
Joel Mueller,

Esiste una corretta implementazione, in grado di gestire qualsiasi tipo di valore: rabdullin.com/journal/2008/12/6/…
Rinat Abdullin

Grazie Rinat, ho davvero ottenuto questo fino a un singolo metodo generico - vedi stackoverflow.com/questions/303287
Adam Lassek

Tutti questi metodi sembrano non essere necessari in quanto è possibile utilizzare la asparola chiave per ottenere un valore da un lettore che consente null. Se si combina l' ??operatore di coalescenza null con l'operatore as, è anche possibile avere un valore predefinito non nullo per passare direttamente a un tipo di valore. Vedere stackoverflow.com/questions/746767/...
stevehipwell

14

Mi ha irritato il fatto che LINQ mi dia un OrderBy che prende come argomento una classe che implementa IComparer, ma non supporta il passaggio in una semplice funzione di confronto anonimo. L'ho corretto.

Questa classe crea un IComparer dalla tua funzione di confronto ...

/// <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
}

... e questi metodi di estensione espongono i miei nuovi sovraccarichi OrderBy su enumerable. Dubito che questo funzioni per LINQ to SQL, ma è ottimo per 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);
    }
}

Se lo desideri, puoi metterlo su codeplex.


13

Questo è per MVC, aggiunge la possibilità di generare un <label />tag per la Htmlvariabile che è disponibile in ogni ViewPage. Speriamo che possa essere utile agli altri che cercano di sviluppare estensioni simili.

Uso:

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

Produzione:

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

Codice:

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

Dai un'occhiata a MvcContrib.FluentHtml
Arnis Lapsa,

Questo probabilmente dovrebbe essere duplicato con Literal invece.
Mark Hurd,

12

Trasforma questo:

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

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

command.Parameters.Add(param);

... in questo:

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

... usando questo metodo di estensione:

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

Altri metodi di estensione ADO.NET: DbExtensions

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.