Was sind Ihre bevorzugten Erweiterungsmethoden für C #? (codeplex.com/extensionoverflow)


478

Lassen Sie uns eine Liste mit Antworten erstellen, in der Sie Ihre hervorragenden und bevorzugten Erweiterungsmethoden veröffentlichen .

Voraussetzung ist, dass der vollständige Code sowie ein Beispiel und eine Erläuterung zur Verwendung veröffentlicht werden.

Aufgrund des großen Interesses an diesem Thema habe ich ein Open Source-Projekt namens extensionoverflow auf Codeplex eingerichtet .

Bitte markieren Sie Ihre Antworten mit einer Annahme, um den Code in das Codeplex-Projekt einzufügen.

Bitte posten Sie den vollständigen Quellcode und keinen Link.

Codeplex News:

24.08.2010 Die Codeplex-Seite ist jetzt hier: http://extensionoverflow.codeplex.com/

11.11.2008 XmlSerialize / XmlDeserialize ist jetzt implementiert und Unit Tested .

11.11.2008 Es ist noch Platz für weitere Entwickler. ;-) JETZT mitmachen !

11.11.2008 Dritter Mitwirkender bei ExtensionOverflow , willkommen bei BKristensen

11.11.2008 FormatWith ist jetzt implementiert und Unit Tested .

09.11.2008 Zweiter Mitwirkender ist ExtensionOverflow beigetreten . Willkommen bei Chakrit .

09.11.2008 Wir brauchen mehr Entwickler. ;-);

09.11.2008 ThrowIfArgumentIsNull in jetzt implementiert und als Einheit getestet auf Codeplex.


Jetzt wird der erste Code an die Codeplex-Site übergeben.
Bovium

Erik leider ist jetzt alles auf Codeplex gestartet. Bitte mach trotzdem mit.
Bovium

3
Sieht sehr gut aus. Ich habe einen Kommentar zur Benennung der statischen Klassen. Die Bezeichnung <Typ> Erweiterungen ist nicht sehr informativ. Zum Beispiel enthält StringExtensions sowohl Formatierungs- als auch XML-Inhalte. Ich denke, es ist besser, die Klasse mit dem Grund zu benennen, warum Sie diesen Typ erweitern. Zum Beispiel UnixDateTimeConversions. Sie können davon ausgehen, dass es Methoden zum Konvertieren in und aus Unix-Zeit enthält. Nur ein Gedanke!
Ecoffey

Überprüfen Sie diese URL für mehr über C # -Erweiterungsmethoden planetofcoders.com/c-extension-methods
Gaurav Agrawal

Antworten:


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

Erlaubt mir zu ersetzen:

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

Mit:

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
Nun, es wird kompiliert, wenn Sie System.Linq verwenden.
Ryu

11
Vielleicht wäre "EqualsAnyOf" ein besserer Name als "In"?
Tom Bushell

10
Ich bin mir nicht sicher, ob es mir gefällt - ich mag die Kürze von In, aber vielleicht IsInwäre es besser.
Winston Smith

50
Mit der gleichen Contains-Methode: (new [] {1, 2, 3}). Contains (a)
Max Toro

4
Ich dachte In<T>(...)auch daran und fand es die nützlichste Erweiterungsmethode außerhalb der Standardbibliothek. Aber ich bin im Widerspruch zum Namen In. Ein Methodenname soll beschreiben, was er tut, Intut dies aber nicht. Ich habe es genannt IsAnyOf<T>(...), aber ich denke, es IsIn<T>(...)wäre auch angemessen.
JBSnorro

160

Ich habe verschiedene Erweiterungsmethoden in meinem MiscUtil- Projekt (die vollständige Quelle ist dort verfügbar - ich werde sie hier nicht wiederholen). Meine Favoriten, von denen einige andere Klassen betreffen (z. B. Bereiche):

Datum und Uhrzeit - hauptsächlich für Unit-Tests. Ich bin mir nicht sicher, ob ich sie in der Produktion verwenden würde :)

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

Reichweiten und Treten - ein großes Dankeschön an Marc Gravell für seine Bedienerarbeit , die dies ermöglicht hat:

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

Vergleiche:

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

Argumentprüfung:

x.ThrowIfNull("x");

LINQ to XML wird auf anonyme Typen (oder andere Typen mit entsprechenden Eigenschaften) angewendet:

// <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 - würde zu lange dauern, um hier zu erklären, aber suchen Sie danach.


1
Das ist schön! Sie sollten es auf Google Code oder CodePlex veröffentlichen, damit ich Ihnen einige Patches senden kann :-) Ich verspreche, dass es lesbar sein wird :-P
Chakrit

3
@bovium: Sie können den Code bereits sehen. Folgen Sie dem Link im ersten Satz - die vollständige Quelle ist da.
Jon Skeet

1
@bovium: Ich mache es lieber selbst, stelle es auf code.google.com und verwalte das Projekt selbst, wenn es dir nichts ausmacht. Natürlich haben Sie die Lizenz, es auf Codeplex zu stellen, wenn Sie die entsprechende Zuordnung beibehalten, aber ich würde es lieber bald selbst klären, es sei denn, Sie sind verzweifelt :)
Jon Skeet

1
@ Jon Skeet. Es steht unter der MIT-Lizenz und ist für alle nutzlos. Kommerziell oder Open Source. Warum nicht zusammenarbeiten und eine Bibliothek mit Erweiterungsmethoden für die Öffentlichkeit erstellen?
Bovium

1
Nur weil ich viele andere Dinge in dieser Bibliothek mache. Sie können gerne eine Kopie davon für Ihr Projekt nehmen, aber ich möchte lieber auch eine Kopie in meinem eigenen Projekt behalten.
Jon Skeet

147

string.Format-Verknüpfung:

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

Beispiel:

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

Zum schnellen Kopieren und Einfügen klicken Sie hier .

Finden Sie es nicht natürlicher, "some string".F("param")statt zu tippen?string.Format("some string", "param") ?

Versuchen Sie einen der folgenden Vorschläge, um einen besser lesbaren Namen zu erhalten:

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
Es ist sicherlich kurz - aber für neue Mitglieder Ihres Teams nicht lesbar.
Jon Skeet

3
Ich denke, Lesbarkeit ist im größeren Schema Ihres Codes wichtiger als ein paar Kurzaussagen, die schnell nachgeschlagen / gefragt werden könnten.
Chakrit

6
Persönlich hätte ich gerne ein separates Formatierungsobjekt, das die BCL einmal analysieren und wiederverwenden könnte. Das würde die Lesbarkeit und Leistung verbessern. Ich habe das BCL-Team gefragt - wir werden sehen ...
Jon Skeet

3
Es ist eine Erweiterungsmethode, die für neue Teammitglieder natürlich nicht lesbar sein wird. Ich dachte, das wäre die Idee mit diesem witzigen Zeug? Woher wissen die neuen Mitglieder sonst, wie klug wir sind?
MarkJ

17
Ok ... Ich habe das gerade in die Tat umgesetzt und bin mit .With - also bekommst du "Dies ist eine {0}". Mit ("Test") und es ist sehr lesbar und macht Sinn. FYI
klkitchens

89

Sind diese von Nutzen?

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

Dies ahmt die Funktion random.choice (seq) von pythons nach. nett.
Daren Thomas

6
Paar Dinge: Ich würde empfehlen, OneOfsollten zu akzeptieren , jede IList<T> . Dann könnten Sie immer auch eine Überladung haben, die ein paramsArgument nimmt und dieses einfach in die IList<T>Überladung übergibt . Ich gab eine Antwort (ganz unten im Moment) mit einer NextBoolähnlichen Methode wie Ihrer CoinToss, aber mit einer Überladung, die einen probabilityParameter benötigt (was ist, wenn 75% der Zeit etwas passieren soll?). Außerdem nur eine Kleinigkeit: Ihr Beispielcode löst ein NullReferenceExceptionDa aus, randdas niemals initialisiert wird.
Dan Tao

3
+1 Ich mag das wirklich, aber ich bevorzuge es CoinToss, mit implementiert zu werden, rng.NextDouble() < .5weil intern .Next(int)mit gemacht wird, .NextDouble()so dass Sie eine Besetzung, ein * und einen Scheck speichern würden.
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;
  }
}

Beispiel:

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

19
Ich liebe dieses, aber ich versuche zu entscheiden, ob es richtig ist, die Grenzen einschließlich des Minimalwerts, aber exklusiv des Maximalwerts zu überprüfen. Ich frage mich, ob das verwirrend wäre. 5.Zwischen (5,10) ist wahr, aber 5.Zwischen (1,5) ist falsch. Ich bin mir nicht einmal sicher, ob eine Companion Within-Methode helfen würde. Gedanken?
Steve Hiner

12
Wäre der Name "IsBetween" nicht sinnvoller? Vielleicht machen Sie auch ein IsBetweenInclusive und IsBetweenExclusive. Keine Ahnung, welche man als Standard nehmen soll.
Fretje

2
@Steve: Es ist sinnvoller, wenn es sich um eine Datetime-Erweiterung handelt.
Joel Coehoorn

16
Für mich bedeutet zwischen: 5.Between (5,10) gibt false zurück und 10.Between (5,10) gibt ebenfalls false zurück. Das fühlt sich für mich einfach natürlich an.
Alex Baranosky

3
Es scheint mir, dass mehrere Menschen unterschiedliche Vorstellungen davon haben, was natürlich ist. Aus diesem Grund sollte wahrscheinlich explizit angegeben werden, was verwendet wird (dh Inklusiv oder Exklusiv), da dies eine sehr einfache Fehlerquelle sein kann.
David Miani

58

Die Erweiterungsmethode:

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

Die Methode gilt für alle Typen und ermöglicht das Hinzufügen einer Reihe von Elementen zu einer Liste als Parameter.

Beispiel:

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

15
Wäre besser als diese IList <T>

21
Verwenden Sie einfach Collection Initializer =>var list = new List<int>{5,4,8,4,2};
Arnis Lapsa

Warum rufen Sie nicht einfach List <T> .AddRange (IEnumerable <T> -Sammlung) in Ihrer Methode auf?
Rauhotz

8
@ Will: Eigentlich wäre es am besten , eine zu akzeptieren ICollection<T>; dann könnte es zum Beispiel auch für LinkedList<T>und HashSet<T>nicht nur für indizierte Sammlungen verwendet werden.
Dan Tao

2
Bearbeitet, um Kovarianz in pre-.net 4.0 zu ermöglichen
BlueRaja - Danny Pflughoeft

55

Setzen Sie dies auf jeden Fall in das Codeplex-Projekt ein.

Objekte in XML serialisieren / deserialisieren:

/// <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
Ich wäre versucht, den ersten ToXml()(wie ToString())
anzurufen

1
Entschuldigung an das OP, wenn er es absichtlich so geschrieben hat, aber die Verwendung von MemoryStreams UND XmlReader / XmlWriter war übertrieben. Die Klassen StringReader und StringWriter sind für diese Operation perfekt.
Portman

2
Achtung, das ist nicht threadsicher. Sie sollten auf jeden Fall Ihren Zugriff auf das Wörterbuch der statischen Serialisierer synchronisieren.
Yann Schwartz

2
@Yann, @T, Es ist viel einfacher, wenn Sie nur das Attribut "thread static" hinzufügen. Dann wird pro Thread ein neuer Cache erstellt. Keine Synchronisation erforderlich.
Frank Krueger

1
@ Jonathan C Dickinson: Aus den MSDN-Dokumenten hier msdn.microsoft.com/en-us/library/… geht hervor, dass der verwendete Konstruktor (neuer XmlSerializer (Typ)) kein Problem mit Speicherverlusten aufweist. Vielleicht wird der Caching-Code nicht benötigt?
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);
    }
}

Naives Beispiel:

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

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

Cooles Beispiel:

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

Hinweis:

Dies ist nicht so, Selectweil Select erwartet wird, dass Ihre Funktion etwas zurückgibt, um es in eine andere Liste umzuwandeln.

Mit ForEach können Sie einfach für jedes Element etwas ausführen, ohne Transformationen / Datenmanipulationen durchführen zu müssen.

Ich habe dies gemacht, damit ich in einem funktionaleren Stil programmieren kann, und ich war überrascht, dass List einen ForEach hat, IEnumerable jedoch nicht.

Fügen Sie dies in das Codeplex-Projekt ein


13
Veröffentlichen Sie, warum die IEnumerable <T> -Erweiterungen von LINQ kein ForEach enthalten: stackoverflow.com/questions/317874/…
Neil

13
Ich empfehle, dies zu lesen, bevor Sie die Methode verwenden: blogs.msdn.com/ericlippert/archive/2009/05/18/…
jpbochi

2
@jpbochi: Dies ist nur Microsoft Demagogie
abatishchev

1
@abatishchev Und dein Kommentar ist nur ein Vorurteil gegen Microsoft. Es macht kein von Eric geschriebenes Wort ungültig. Jemandes Argumente werden nicht nur aufgrund des Unternehmens, für das er / sie arbeitet, gültig oder ungültig gemacht.
Jpbochi

1
Lassen Sie mich übrigens einen Punkt klarstellen. Ich habe nicht gesagt, dass Sie diese ForEach-Erweiterungsmethode nicht verwenden sollten. Ich habe nur gesagt, dass Sie die Punkte berücksichtigen sollten, die Eric enthüllt hat, bevor Sie entscheiden, ob Sie es verwenden oder nicht. Ich habe es gelesen und beschlossen, es nicht zu benutzen. Sie können mit Ihrem Code tun, was Sie wollen.
Jpbochi

43

Meine Konvertierungserweiterungen, mit denen Sie Folgendes tun können:

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

Hier ist es, wie auf TheSoftwareJedi.com veröffentlicht

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

Sie können bei einem Fehler nach der Standardeinstellung fragen (ruft den leeren Konstruktor oder "0" für Zahlen auf), einen "Standard" -Wert angeben (ich nenne ihn "andere") oder nach null fragen (wobei T: class). Ich habe auch sowohl stille Ausnahmemodelle als auch ein typisches TryParse-Modell bereitgestellt, das einen Bool zurückgibt, der die ausgeführte Aktion angibt, und ein out-Parameter enthält den neuen Wert. Unser Code kann also solche Dinge tun

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

Ich konnte Nullable-Typen nicht dazu bringen, sehr sauber in das Ganze zu rollen. Ich habe es ungefähr 20 Minuten lang versucht, bevor ich das Handtuch geworfen habe.


64
Persönlich bin ich kein Fan von Code, der versucht, das Ergebnis zu bestimmen. Try / Catch sollte für Fehler verwendet werden, die außerhalb der beabsichtigten Logik IMO auftreten. hmmmmm
Pure.Krome

Wenn ich nicht wollte, dass Sie den Code verwenden, hätte ich ihn nicht gepostet! :)
TheSoftwareJedi

Endlich etwas Unsichtbares. Ich mag das. :)
Arnis Lapsa

8
Sie sollten diese "catch" -Klausel zumindest so ändern, dass nur die Ausnahmen abgefangen werden, die ChangeType () auslöst, wenn die Referenz nicht "konvertiert" werden kann. Ich denke, Sie möchten nicht, dass OutOfMemoryException, ExecutionEngineException, ThreadAbortException oder ähnliches als Konvertierungsfehler behandelt werden. Diese Dinge werden sonst ziemlich schwer zu verfolgen sein.
Christian.K

2
Ich glaube, es ToOrNullhat genau das gleiche Verhalten wie ToOrDefault(dh wenn Sie ToOrDefaulteinen Referenztyp mit einer erfolglosen Konvertierung aufrufen , wird er zurückgegeben null). Aber was noch wichtiger ist, es scheint mir irgendwie überflüssig zu sein, da es var s = myObject as stringdasselbe erreicht wie var s = myObject.ToOrNull<string>()- aber ohne möglicherweise einen fangen zu müssen InvalidCastException. Vermisse ich etwas
Dan Tao

43

Ich habe eine Erweiterungsmethode zum Protokollieren von Ausnahmen:

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

Und es wird so verwendet:

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

[Entschuldigung für die zweimalige Veröffentlichung; der 2. ist besser gestaltet :-)]


2
Sollte public static void Log (diese Ausnahme obj) {} vielleicht lesen?
Chris S

Ich denke, dies ist gut für BCL- oder Drittanbieterausnahmen, aber wenn Sie Ihre eigenen Ausnahmetypen rollen, können Sie die Protokollierung in Ihre Basisausnahmeklasse einfügen. Auf diese Weise müssen Sie nicht daran denken, Log () aufzurufen.
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);
    }
}

Nützlich, um eine Zeichenfolge in eine Aufzählung zu analysieren.

public enum TestEnum
{
    Bar,
    Test
}

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

Kredit geht an Scott Dorman

--- Für Codeplex-Projekt bearbeiten ---

Ich habe Scott Dorman gefragt, ob es ihm etwas ausmachen würde, wenn wir seinen Code im Codeplex-Projekt veröffentlichen. Dies ist die Antwort, die ich von ihm bekommen habe:

Vielen Dank für das Heads-up sowohl zum SO-Post als auch zum CodePlex-Projekt. Ich habe Ihre Antwort auf die Frage positiv bewertet. Ja, der Code ist derzeit gemeinfrei unter der CodeProject Open License ( http://www.codeproject.com/info/cpol10.aspx ).

Ich habe keine Probleme damit, dass dies in das CodePlex-Projekt aufgenommen wird. Wenn Sie mich zum Projekt hinzufügen möchten (Benutzername ist sdorman), füge ich diese Methode sowie einige zusätzliche Enum-Helfer-Methoden hinzu.


Dieses Enum-Parsing-Szenario
taucht

Wow, ich habe Methoden geschrieben, um Zeichenfolgen Enums zuzuordnen (habe gerade angefangen, .NET zu verwenden). Danke, das wird absolut helfen!
Kevin

4
Sie können dieses ToEnum <> () auch benennen, da es nach dem Objekt steht.
Neil

Beachten Sie, dass Enum.TryParse <T> zu Net 4.0 hinzugefügt wurde - blogs.msdn.com/bclteam
Dan Diplo

1
Ich denke nicht, dass diese Methode Trim verwenden sollte. Das Trimmen der Eingabe sollte in der Verantwortung des Anrufers liegen.
CodesInChaos

32

Ich finde das ziemlich nützlich:

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

Sie können es auf CodePlex verwenden.


2
Kann jemand so freundlich sein, es den weniger Begabten von uns zu erklären?
Jpbochi

hahaha Lies einfach den Artikel (Joels Kommentar oben) - lustig wahr, aber nachdem ich so ziemlich im selben Boot war (am empfangenden Ende, nicht am Paula-Ende), ist es nur lustig, wenn ich zurückblicke! Nachdem ein Auftragnehmer zur Arbeit an einem Projekt hinzugezogen worden war, war ich Konstrukteurin / leitende Entwicklerin - sie stand nicht unter meiner direkten Kontrolle, sondern erhielt Arbeit von der Arbeitsliste meines Teams. Die Bosse lobten sie als brillant (und stellten sie später sogar wieder als Dev Lead ein!). Es wurde ihnen nie klar, dass jeder Code, den sie schrieb oder entwarf, es nicht in die Produktion geschafft hatte und alle von meinem Team komplett neu geschrieben werden mussten!
Wolf5370

31

DateTimeExtensions

Beispiele:

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
Ich würde vorschlagen, "SetTime" in "WithTime" umzubenennen, da es nicht tatsächlich auf den vorhandenen Wert gesetzt wird. Ansonsten aber schön.
Jon Skeet

28
DateTime.Now.First () - zuerst was? Dies geht nur aus dem Beispielcode hervor.
Mackenir

2
Sehr schön. Aber stimmen Sie zu, dass die Namen viel besser sein könnten.
Bovium

DateTime.Now.First ist in Intellisense klar genug, wenn die Methode gut dokumentiert ist.
Ryan Lundy

29

gitorious.org/cadenza ist eine vollständige Bibliothek mit einigen der nützlichsten Erweiterungsmethoden, die ich gesehen habe.


12 ziemlich grundlegende Erweiterungsmethoden. Ich bin ein bisschen überwältigt von Monosteinen.
Mackenir

(Ich spreche von der veröffentlichten Version, nicht von der, für die Sie die Quellcodeverwaltung verwenden müssen)
Mackenir

28

Hier ist eine, die ich häufig für die Formatierung von Präsentationen verwende.

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, die Behandlung von Pokemon-Ausnahmen wird Probleme wie ThreadAbortException usw. verbergen. Bitte fangen Sie etwas Bestimmtes ab.
JBRWilkinson

28

Hier ist ein Hin und Her für römische Ziffern. Nicht oft verwendet, könnte aber praktisch sein. Verwendungszweck:

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

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

Die Quelle:

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

Das erinnert mich an den Python PEP 313, das ein Aprilscherz war römische Ziffer Literale in Python umfassen: python.org/dev/peps/pep-0313
natorische

25

Ein bequemer Weg, um mit Größen umzugehen:

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

Meiner Meinung nach ist dies ein wirklich schlechter Codierungsstil. Stattdessen sollten Konstanten verwendet werden, keine verschleierte Logik.
xxbbcc

24

Für Winform Controls:

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

IsDesignTime Verwendung:

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

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

Ich habe vergessen zu erwähnen, zögern Sie nicht, diese auf Codeplex zu verwenden ...


1
Wie bereits erwähnt, gilt dies nur für WinForms. Es funktioniert möglicherweise mit WPF, aber es gibt Probleme (beschrieben im Kommentar zu WPF unter msdn.microsoft.com/en-us/library/… ). Die beste Lösung für WPF, die ich gefunden habe, ist in geekswithblogs.net/lbugnion/archive/2009/09/05/… beschrieben (obwohl es sich um eine statische Eigenschaft handelt, funktioniert sie nicht wirklich als Erweiterungsmethode.)
scobi

23

Das ThrowIfArgumentIsNull ist eine gute Möglichkeit, diese Nullprüfung durchzuführen, die wir alle durchführen sollten.

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

Im Folgenden finden Sie die Verwendung und es funktioniert für alle Klassen in Ihrem Namespace oder überall dort, wo Sie den Namespace verwenden.

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

Es ist in Ordnung, diesen Code im CodePlex- Projekt zu verwenden.


Ich mag das auch, Jon hat es in seinem und ich benutze etwas Ähnliches von Umbrella, könnte es ertragen, den Teil "ArgumentIs" fallen zu lassen.
cfeduke

Ja! Dies ist auch eine Kewl-Erweiterungsmethode :)
Pure.Krome

3
Wenn Sie den ArgumentNullException-Konstruktor mit nur 1 Zeichenfolgenargument verwenden, muss dieses Argument nur der Parametername und nicht die Fehlermeldung sein. Ihr Code sollte also folgendermaßen aussehen: if (obj == null) löst eine neue ArgumentNullException (parameterName) aus;
Tommy Carlier

Ich würde dafür verwenden default(T)und die Klassenanforderung entfernen.
Joel Coehoorn

1
@Joel: Nicht standardmäßige Werte für native Typen sind häufiger legitime Argumente als Nullwerte. Das Prüfen gegen Null ist für mich sinnvoller als das Prüfen gegen Standard. Natürlich verallgemeinere ich die ganze Idee nur mit Require.ThatArgument(input != null)oder Require.ThatArgument(personId > 0). Es braucht nicht viel mehr Code, es ist viel flexibler und es liest sich gut. Ich habe zusätzliche Überschreibungen, die Funktionen benötigen, wenn Sie die Fehlermeldung oder die Ausnahme selbst anpassen möchten.
StriplingWarrior

22

Ich vermisse die With-Anweisung von Visual Basic, wenn ich zu C # wechsle.

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

Und so verwenden Sie es in C #:

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

Spart viel Tipparbeit!

Vergleichen Sie dies mit:

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

Codeplex-Projekt einfügen


4
Nur eine Vermutung, aber denken Sie darüber nach, was passiert, wenn Ihr T eine Struktur ist.
Rauhotz

5
Wo immer möglich, verwende ich auch die Initialisierersyntax der c # 3.0-Eigenschaft, um das gleiche Ergebnis zu erzielen.
Steve

3
@ Chakrit, hier ist ein Beispiel. Dies gilt nur beim Erstellen des Objekts. Button n = new Button {Name = "Button1", Breite = 100, Höhe = 20, Aktiviert = wahr};
Steve

1
Dies ist nützlich, wenn Sie viele Ereignisse verbinden müssen, da die Eigenschaftsinitialisierersyntax von C # keine Ereignisse unterstützt.
Gabe

1
Dies ist auch außerhalb von Eigenschaftsinitialisierern nützlich, da Sie sie nur beim Erstellen eines neuen Objekts verwenden können. Diese Erweiterung kann für zuvor erstellte Objekte verwendet werden.
Brady Moritz

18

Nimmt ein camelCaseWord oder PascalCaseWord und "formuliert" es, dh 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])" ) );
}

Ich benutze es oft in Verbindung mit Capitalize

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

Anwendungsbeispiel

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

Kostenlose Verwendung in Codeplex-Projekten


Das Aggregat in Großschreibung ist für die Leistung ziemlich schlecht, da es viele Zeichenfolgeninstanzen erstellt. Warum nicht stattdessen word.Substring (1) verwenden?
Thomas Levesque

17

Ich fand das hilfreich

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

Dadurch wird die Nullprüfung im aufrufenden Code entfernt. Du könntest es jetzt tun

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

Ja, wenn jemand "Null Object Pattern" vergessen hat, ist diese Methode nützlich, um es zu patchen. Die Sammlung sollte niemals null sein.
Pavel Hodek

16

Konvertieren Sie ein Double in einen String, der mit der angegebenen Kultur formatiert wurde:

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

Beispiel:

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

13
Sie sollten Decimal für die Währung verwenden, da sonst Rundungsprobleme auftreten
Andrew Bullock,

Was ist mit einer Aufzählung im Parameter anstelle einer einfachen Zeichenfolge
Regeln

15

Unten finden Sie eine Erweiterungsmethode, die den Code von Rick Strahl anpasst (und auch die Kommentare) , damit Sie bei jeder Konvertierung in eine Zeichenfolge nicht mehr die Bytereihenfolge eines Bytearrays oder einer Textdatei erraten oder lesen müssen.

Mit dem Snippet können Sie einfach Folgendes tun:

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

Wenn Sie Fehler finden, fügen Sie diese bitte zu den Kommentaren hinzu. Fühlen Sie sich frei, es in das Codeplex-Projekt aufzunehmen.

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

Sehr nützliche Methode, aber ich denke nicht, dass es eine Erweiterungsmethode sein sollte.
Pop Catalin

Wenn Sie einen Texteditor schreiben, ist wahrscheinlich eine Erweiterungsmethode erforderlich, aber ich stimme zu, dass es die meiste Zeit wahrscheinlich nicht mehr als eine statische private Methode ist
Chris S

15

Hier ist eine, die ich heute erstellt habe.

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

Damit können Sie Folgendes tun:

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

Das ist fließender und (IMO) leichter zu lesen als dies:

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

1
Was ist, wenn ich will thingy.NullOr(t => t.Count), wo Countist ein Int? Sie sollten default(TReturn)statt null zurückgeben, auf diese Weise benötigen Sie die classEinschränkung nicht und sie funktioniert auch für Werttypen
Thomas Levesque

2
TIn sollte eine Klasse sein, sonst macht diese gesamte Erweiterungsmethode keinen Sinn (Werttypen dürfen nicht null sein). Und Ihr Beispiel mit t.Count funktioniert mit der obigen Erweiterungsmethode. Könnten Sie einen zweiten Blick darauf werfen?
Scobi

@Scott: Dies ist eine nützliche Methode für ein häufiges Problem. Allerdings glaube ich, TReturn elseValue = default(TReturn)ist nur für .NET 4.0 verfügbar? Ich habe 3.5 SP1 und ich habe dieses Konstrukt noch nie gesehen (mein Compiler auch nicht). Ich habe dies nur in die Methode verschoben. Ein Problem ist jedoch, dass das Boxen eines nullbaren Typs in ein Objekt zur Verwendung mit der Methode ein unerwartetes Ergebnis liefert (0 gegenüber erwarteter Null).
Jim Schubert

@ Jim: Das default(T)Schlüsselwort ist seit VS2005 vorhanden, aber ich denke, Standardparameter sind eine neue .NET 4-Funktion. Der einfache Weg, dies zu umgehen, sollte darin bestehen, zwei Varianten zu haben, eine, die den Parameter übernimmt, und eine, die dies nicht tut. Ich werde die Antwort so aktualisieren, dass sie CLR 2.0-kompatibel ist. In Bezug auf das Boxen - das ist der Punkt von default. Es handelt sich um 0-initialisierte Daten für einen Werttyp und null für alle Referenztypen. Eine TReturn eines Wertetyps sollte während der gesamten Funktion nicht in der Box bleiben.
Scobi

@Scott: Meine Frage betraf den Standardparameter, den ich nur in dynamischen Sprachen wie Ruby gesehen habe. Mein Punkt in Bezug auf nullfähige Typen ist, dass x.Valuedie Rückgabe null zurückgeben sollte (wenn zum Beispiel int?null war) oder den Wert, wenn er int?einen Wert hat. Es ist ein seltsamer Fall, 0wenn zurückgegeben int? x = nullwird, wenn es übergeben und an das Objekt verpackt wird. Ich habe ähnliche Überprüfungen für nullfähige Typen in Bibliotheken wie fließend nhibernate und linfu (glaube ich) für diesen speziellen Fall gesehen, sodass Sie die Klassenbeschränkung wie zuvor vorgeschlagen aufheben können.
Jim Schubert

14

"Bitte markieren Sie Ihre Antworten mit einer Annahme, um den Code in das Codeplex-Projekt einzufügen."

Warum? Alle Sachen auf dieser Seite unter CC-by-sa-2.5 . Stellen Sie Ihr Erweiterungsüberlaufprojekt also einfach unter dieselbe Lizenz, und Sie können es frei verwenden.

Wie auch immer, hier ist eine String.Reverse-Funktion, die auf dieser Frage basiert .

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

Implementiert String IEnumerable <char> nicht bereits? Sie müssen also nur einen neuen String (input.Reverse ()) zurückgeben.
Iain Galloway

Eine Implementierung mit StringBuilder sollte schneller sein.
CodesInChaos

1
@CodeInChaos Beim Benchmarking in stackoverflow.com/questions/228038 wurde gemessen, dass StringBuilder langsamer ist.
Michael Stum

Du hast recht. Es scheint, als würden die Thread-Sicherheitsanforderungen (wahrscheinlich um die Unveränderlichkeit der von ToString zurückgegebenen Zeichenfolge sicherzustellen) StringBuilder erheblich verlangsamen.
CodesInChaos

2
Ich hoffe, Sie begegnen keinen Ersatz- oder Kombinationszeichen.
Dalle

14

Ich hatte es satt, mühsam Null zu überprüfen, während ich Werte aus MySqlDataReader zog, also:

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

Dies kann natürlich mit jedem SqlDataReader verwendet werden.


Sowohl Hangy als auch Joe hatten einige gute Kommentare dazu, und ich hatte seitdem die Gelegenheit, etwas Ähnliches in einem anderen Kontext zu implementieren. Hier ist eine andere Version:

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
Dies sollte auch als Erweiterungsmethode für IDataReader funktionieren.
Hangy

2
Stellen Sie den Parameter "this" vom Typ IDataRecord ein, um maximale Kompatibilität zu gewährleisten. In meiner Version davon habe ich eine Überladung, die eine Ordnungszahl annimmt, die die fieldName-Version aufruft. Speichert das "GetOrdinal", gefolgt von einer Suche nach Namen.
Joel Mueller

Es gibt eine ordnungsgemäße Implementierung, die mit jedem Werttyp
Rinat Abdullin

Vielen Dank, Rinat, ich habe dies tatsächlich auf eine einzige generische Methode reduziert
Adam Lassek

Alle diese Methoden scheinen nicht erforderlich zu sein, da Sie das asSchlüsselwort verwenden können, um einen Wert von einem Reader abzurufen, der null zulässt. Wenn Sie den Null-Koaleszenzoperator ??mit dem as-Operator kombinieren , können Sie sogar einen Standardwert ungleich Null haben, um direkt zu einem Werttyp zu wechseln. Siehe stackoverflow.com/questions/746767/…
stevehipwell

14

Es hat mich irritiert, dass LINQ mir ein OrderBy gibt, das eine Klasse verwendet, die IComparer als Argument implementiert, aber die Übergabe einer einfachen anonymen Vergleichsfunktion nicht unterstützt. Ich habe das korrigiert.

Diese Klasse erstellt einen IComparer aus Ihrer Vergleichsfunktion ...

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

... und diese Erweiterungsmethoden legen meine neuen OrderBy-Überladungen für Enumerables offen. Ich bezweifle, dass dies für LINQ to SQL funktioniert, aber es ist großartig für 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);
    }
}

Sie können dies gerne auf Codeplex setzen, wenn Sie möchten.


13

Dieser ist für MVC gedacht und bietet die Möglichkeit <label />, der HtmlVariablen, die in jedem Variablen verfügbar ist , ein Tag zu generieren ViewPage. Hoffentlich wird es für andere von Nutzen sein, die versuchen, ähnliche Erweiterungen zu entwickeln.

Verwenden:

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

Ausgabe:

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

Code:

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

Überprüfen Sie heraus MvcContrib.FluentHtml
Arnis Lapsa

Dies sollte wahrscheinlich stattdessen mit Literal dupliziert werden.
Mark Hurd

12

Drehen Sie dies:

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

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

command.Parameters.Add(param);

... das sehr gut finden:

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

... mit dieser Erweiterungsmethode:

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

Weitere ADO.NET-Erweiterungsmethoden: DbExtensions

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.