Quelles sont vos méthodes d'extension préférées pour C #? (codeplex.com/extensionoverflow)

478

Faisons une liste de réponses où vous postez vos excellentes méthodes d'extension préférées .

L'exigence est que le code complet doit être publié et un exemple et une explication sur la façon de l'utiliser.

Sur la base du grand intérêt pour ce sujet, j'ai configuré un projet Open Source appelé extensionoverflow sur Codeplex .

Veuillez marquer vos réponses avec une acceptation pour mettre le code dans le projet Codeplex.

Veuillez publier le code source complet et non un lien.

Actualités Codeplex:

24.08.2010 La page Codeplex est maintenant ici: http://extensionoverflow.codeplex.com/

11.11.2008 XmlSerialize / XmlDeserialize est maintenant implémenté et testé unitaire .

11.11.2008 Il y a encore de la place pour plus de développeurs. ;-) Rejoignez-nous MAINTENANT!

11.11.2008 Un troisième contributeur rejoint ExtensionOverflow , bienvenue à BKristensen

11.11.2008 FormatWith est maintenant implémenté et testé à l'unité .

09.11.2008 Le deuxième contributeur a rejoint ExtensionOverflow . bienvenue sur chakrit .

09.11.2008 Nous avons besoin de plus de développeurs. ;-)

09.11.2008 ThrowIfArgumentIsNull est désormais implémenté et testé sur Codeplex.

bovium
la source
Maintenant, le premier code est validé sur le site Codeplex.
bovium
Erik malheureusement tout est démarré maintenant sur codeplex. Veuillez vous joindre quand même.
bovium
3
Ça a l'air plutôt bien. J'ai un commentaire sur le nom des classes statiques. Les nommer <type> Extensions n'est pas très informatif. Par exemple, StringExtensions contient à la fois des éléments de formatage et xml. Je pense qu'il vaut mieux nommer la classe avec la raison pour laquelle vous étendez ce type. Par exemple UnixDateTimeConversions. Vous pouvez raisonnablement deviner qu'il contient des méthodes de conversion vers et depuis le temps Unix. Juste une pensée!
ecoffey
Consultez cette URL pour en savoir plus sur les méthodes d'extension C # planetofcoders.com/c-extension-methods
Gaurav Agrawal

Réponses:

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

Me permet de remplacer:

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

Avec:

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

and

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

and

if(reallyLongMethodParameterName.In(SomeEnum.Value1, SomeEnum.Value2, SomeEnum.Value3, SomeEnum.Value4)
{
  // do something....
}
Winston Smith
la source
2
Eh bien, il se compile si vous utilisez System.Linq;
Ryu
11
Peut-être que "EqualsAnyOf" serait un meilleur nom que "In"?
Tom Bushell
10
Je ne suis pas sûr de l'aimer - j'aime la brièveté de In, mais ce IsInserait peut -être mieux.
Winston Smith
50
Utilisation de la même méthode Contains: (new [] {1, 2, 3}) Contains (a)
Max Toro
4
J'y ai pensé In<T>(...)aussi et j'ai trouvé que c'était la méthode d'extension la plus utile en dehors de la bibliothèque standard. Mais je suis en désaccord avec le nom In. Un nom de méthode est censé décrire ce qu'il fait, mais Inne le fait pas. Je l'ai appelé IsAnyOf<T>(...), mais je pense que ce IsIn<T>(...)serait suffisant aussi.
JBSnorro
160

J'ai différentes méthodes d'extension dans mon projet MiscUtil (la source complète est disponible là-bas - je ne vais pas la répéter ici). Mes favoris, dont certains impliquent d'autres classes (comme les gammes):

Date et heure - principalement pour les tests unitaires. Je ne suis pas sûr de les utiliser en production :)

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

Gammes et pas - merci énormément à Marc Gravell pour son travail d' opérateur pour rendre cela possible:

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

Comparaisons:

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

Vérification des arguments:

x.ThrowIfNull("x");

LINQ to XML appliqué aux types anonymes (ou à d'autres types avec des propriétés appropriées):

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

Appuyez sur LINQ - serait trop long à expliquer ici, mais recherchez-le.

Jon Skeet
la source
1
C'est zonte! Vous devriez le mettre sur Google Code ou CodePlex pour que je puisse vous envoyer des correctifs :-) Je promets que ce sera lisible :-P
chakrit
3
@bovium: Vous pouvez déjà voir le code. Suivez le lien dans la première phrase - la source complète est là.
Jon Skeet
1
@bovium: Je préfère le faire moi-même, le mettre sur code.google.com et gérer le projet moi-même, si cela ne vous dérange pas. Évidemment, vous êtes dans la licence pour le mettre sur Codeplex si vous conservez l'attribution appropriée, mais je préfère le trier moi-même bientôt, sauf si vous êtes désespéré :)
Jon Skeet
1
@Jon Skeet. Il est mis sous licence MIT et gratuit pour tout le monde. Commercialement ou open source. Pourquoi ne pas unir vos forces et créer une bibliothèque de méthodes d'extension pour le public.
bovium
1
Tout simplement parce que je fais beaucoup d'autres morceaux dans cette bibliothèque. Vous pouvez en prendre une copie pour votre projet, mais je préfère également en conserver une copie dans mon propre projet.
Jon Skeet
147

string.Format raccourci:

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

Exemple:

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

Pour copier-coller rapidement, cliquez ici .

Ne trouvez-vous pas plus naturel de taper à la "some string".F("param")place string.Format("some string", "param")?

Pour un nom plus lisible , essayez l'une de ces suggestions:

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

..

chakrit
la source
11
C'est certainement court - mais il sera illisible pour tout nouveau membre de votre équipe.
Jon Skeet
3
Je pense que la lisibilité compte plus dans le schéma plus grand de votre code que quelques déclarations abrégées qui pourraient être rapidement recherchées / demandées.
chakrit
6
Personnellement, j'aimerais un objet Formatter séparé, que le BCL pourrait analyser le motif d'une fois et réutiliser. Cela augmenterait la lisibilité et les performances. J'ai demandé à l'équipe BCL - nous verrons ...
Jon Skeet
3
C'est une méthode d'extension, bien sûr, elle sera illisible pour les nouveaux membres de l'équipe. Je pensais que c'était l'idée avec ce truc plein d'esprit? Sinon, comment les nouveaux membres sauront-ils à quel point nous sommes intelligents?
MarkJ
17
Ok ... Je suis juste allé mettre cela en action et je suis allé avec .Avec - donc vous obtenez "Ceci est un {0}". Avec ("test") et c'est très lisible et logique. FYI
klkitchens
89

Est-ce utile?

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

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

Random rand;
bool luckyDay = rand.CoinToss();
string babyName = rand.OneOf("John", "George", "Radio XBR74 ROCKS!");
xyz
la source
cette fonction imite la fonction random.choice (seq) des pythons. agréable.
Daren Thomas
6
Quelques choses: je recommanderais que l' OneOfon accepte tout IList<T> . Ensuite , vous pouvez toujours aussi avoir une surcharge qui prend un paramsarg et passe juste que dans la IList<T>surcharge. J'ai donné une réponse (bien en bas en ce moment) avec une NextBoolméthode similaire à la vôtre CoinToss, mais avec une surcharge qui prend un probabilityparamètre (et si je veux que quelque chose se produise 75% du temps?). Aussi, juste un choix: votre exemple de code lancera un NullReferenceExceptionpuisque randn'est jamais initialisé.
Dan Tao
3
+1 J'aime vraiment ça, mais je préfère CoinTossêtre implémenté avec, rng.NextDouble() < .5car en interne, il .Next(int)est fait avec .NextDouble()pour que vous enregistriez un casting, un * et un chèque.
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;
  }
}

Exemple:

if (myNumber.Between(3,7))
{
  // ....
}
CMS
la source
19
J'adore celui-ci mais j'essaie de décider s'il est juste de vérifier les limites inclusivement sur la valeur minimale mais exclusive sur la valeur maximale. Je me demande si ce serait déroutant. 5.Entre (5, 10) est vrai mais 5.Entre (1,5) est faux. Je ne suis même pas sûr qu'une méthode compagnon dans le cadre serait utile. Réflexions?
Steve Hiner
12
Le nom "IsBetween" n'aurait-il pas plus de sens? Peut-être aussi faire un IsBetweenInclusive et IsBetweenExclusive. Aucune idée de celui à prendre par défaut.
fretje
2
@Steve: cela a plus de sens s'il s'agissait d'une extension datetime.
Joel Coehoorn
16
Pour moi, cela signifie: 5.Entre (5,10) renvoie faux, et 10.Entre (5,10) renvoie également faux. Cela me semble naturel.
Alex Baranosky
3
Il me semble que plusieurs personnes ont des idées différentes sur ce qui est naturel. Pour cette raison, il convient probablement d'indiquer explicitement ce qui est utilisé (c'est-à-dire Inclusif vs Exclusif), car cela pourrait être une source très facile d'erreurs.
David Miani
58

La méthode d'extension:

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

La méthode s'applique à tous les types et vous permet d'ajouter une plage d'éléments à une liste en tant que paramètres.

Exemple:

var list = new List<Int32>();
list.AddRange(5, 4, 8, 4, 2);
stiduck
la source
15
Ce serait mieux que cet IList <T>
21
Utilisez simplement l'initialiseur de collection =>var list = new List<int>{5,4,8,4,2};
Arnis Lapsa
Pourquoi ne pas simplement appeler List <T> .AddRange (collection IEnumerable <T>) dans votre méthode?
Rauhotz
8
@Will: En fait, il serait préférable d'accepter un ICollection<T>; alors il pourrait également être utilisé sur, par exemple, LinkedList<T>et HashSet<T>pas seulement sur des collections indexées.
Dan Tao
2
Modifié pour autoriser la covariance dans pre-.net 4.0
BlueRaja - Danny Pflughoeft
55

Mettez cela dans le projet codeplex.

Sérialisation / désérialisation d'objets en XML:

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

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

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

    var serializer = new XmlSerializer(typeof(T));
    using (var reader = new StringReader(xml))
    {
        try { return (T)serializer.Deserialize(reader); }
        catch { return null; } // Could not be deserialized to this type.
    }
}
TWith2Sugars
la source
8
Je serais tenté d'appeler le premier ToXml()(comme ToString())
Jay Bazuzi
1
Toutes mes excuses à l'OP s'il l'a intentionnellement écrit de cette façon, mais l'utilisation de MemoryStreams ET XmlReader / XmlWriter était exagérée. Les classes StringReader et StringWriter sont parfaites pour cette opération.
Portman
2
Attention, ce n'est pas threadsafe. Vous devez absolument synchroniser votre accès au dictionnaire serialisers statique.
Yann Schwartz
2
@Yann, @T, c'est beaucoup plus facile si vous ajoutez simplement l'attribut "thread statique". Ensuite, un nouveau cache sera créé par thread. Pas besoin de synchronisation.
Frank Krueger
1
@Jonathan C Dickinson: Il ressort des documents MSDN ici msdn.microsoft.com/en-us/library/… que le constructeur utilisé (nouveau XmlSerializer (type)) n'a pas de problème de fuite de mémoire. Alors peut-être que le code de mise en cache n'est pas nécessaire?
slolife
46

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

Exemple naïf:

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

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

Exemple sympa:

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

Remarque:

Ce n'est pas comme Selectparce Select que votre fonction attend de retourner quelque chose comme pour la transformation en une autre liste.

ForEach vous permet simplement d'exécuter quelque chose pour chacun des éléments sans aucune transformation / manipulation de données.

J'ai fait cela pour pouvoir programmer dans un style plus fonctionnel et j'ai été surpris que List ait un ForEach alors que IEnumerable n'en a pas.

Mettez cela dans le projet codeplex

chakrit
la source
13
Publiez pourquoi les extensions IEnumerable <T> de LINQ n'incluent pas de ForEach: stackoverflow.com/questions/317874/…
Neil
13
Je recommande de lire ceci avant d'utiliser la méthode: blogs.msdn.com/ericlippert/archive/2009/05/18/…
jpbochi
2
@jpbochi: Ce n'est que de la démagogie Microsoft
abatishchev
1
@abatishchev Et votre commentaire n'est qu'un préjugé contre Microsoft. Il n'invalide aucun mot écrit par Eric. Les arguments de quelqu'un ne sont pas validés ou invalides uniquement en raison de l'entreprise pour laquelle il / elle travaille.
jpbochi
1
Soit dit en passant, permettez-moi de préciser un point. Je n'ai pas dit que vous ne devriez pas utiliser cette méthode d'extension ForEach. Je viens de dire que vous devriez considérer les points qu'Eric a exposés avant de décider de l'utiliser ou non. Je l'ai lu et j'ai décidé de ne pas l'utiliser. Vous êtes libre de faire ce que vous voulez avec votre code.
jpbochi
43

Mes extensions de conversion qui vous permettent de faire:

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

Le voici, tel que publié sur 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;
    }
}

Vous pouvez demander la valeur par défaut (appelle un constructeur vide ou "0" pour les chiffres) en cas d'échec, spécifier une valeur "par défaut" (je l'appelle "autre"), ou demander la valeur nulle (où T: classe). J'ai également fourni à la fois des modèles d'exception silencieux et un modèle TryParse typique qui renvoie un booléen indiquant l'action entreprise, et un paramètre de sortie contient la nouvelle valeur. Donc, notre code peut faire des choses comme ça

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

Je ne pouvais pas faire rouler les types Nullable dans le tout très proprement. J'ai essayé pendant environ 20 minutes avant de jeter l'éponge.

TheSoftwareJedi
la source
64
Personnellement, je ne suis pas un fan de code qui essaie / attrape pour déterminer le résultat. Try / catch doit être utilisé pour les erreurs qui se produisent en dehors de la logique prévue, IMO. hmmmmm
Pure.Krome
Si je ne voulais pas que vous utilisiez le code, je ne l'aurais pas posté! :)
TheSoftwareJedi
Enfin quelque chose d'invisible. Je l'aime. :)
Arnis Lapsa
8
Vous devez au moins modifier cette clause "catch" pour intercepter uniquement les exceptions que ChangeType () lèvera lorsqu'il ne pourra pas "convertir" la référence. Je pense que vous ne voudriez pas qu'une OutOfMemoryException, ExecutionEngineException, ThreadAbortException ou similaire soit traitée comme une erreur de conversion. Sinon, ces choses seront assez difficiles à suivre pour détecter les erreurs.
Christian.K
2
Je crois qu'il ToOrNulla exactement le même comportement que ToOrDefault(c'est-à-dire que si vous appelez ToOrDefaultun type de référence avec une conversion infructueuse, il reviendra null). Mais plus important encore, cela me semble un peu redondant car il var s = myObject as stringaccomplit la même chose que var s = myObject.ToOrNull<string>()- mais sans potentiellement avoir à en attraper un InvalidCastException. Suis-je en train de manquer quelque chose?
Dan Tao
43

J'ai une méthode d'extension pour enregistrer les exceptions:

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

Et il est utilisé comme ceci:

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

[désolé d'avoir posté deux fois; le 2ème est mieux conçu :-)]

Charlie
la source
2
Doit lire le journal public void (cet obj d'exception) {} peut-être?
Chris S
Je pense que cela est bon pour les exceptions BCL ou tierces, mais si vous lancez vos propres types d'exception, vous pouvez placer la journalisation dans votre classe d'exception de base. De cette façon, vous n'avez pas à vous rappeler d'appeler 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 pour analyser une chaîne dans un Enum.

public enum TestEnum
{
    Bar,
    Test
}

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

Le mérite revient à Scott Dorman

--- Modifier pour le projet Codeplex ---

J'ai demandé à Scott Dorman s'il voulait bien que nous publions son code dans le projet Codeplex. Voici la réponse que j'ai reçue de lui:

Merci pour les informations sur le poste SO et le projet CodePlex. J'ai surévalué votre réponse à la question. Oui, le code est effectivement dans le domaine public actuellement sous la licence ouverte CodeProject ( http://www.codeproject.com/info/cpol10.aspx ).

Je n'ai aucun problème à ce que cela soit inclus dans le projet CodePlex, et si vous voulez m'ajouter au projet (le nom d'utilisateur est sdorman), j'ajouterai cette méthode ainsi que des méthodes d'assistance enum supplémentaires.

mlarsen
la source
Ce scénario d'analyse d'énumération revient tout le temps ... je dois le mettre dans ma
bibliothèque
Wow, j'ai écrit des méthodes pour mapper des chaînes à des énumérations (je viens de commencer à utiliser .NET). Merci, cela vous aidera absolument!
Kevin
4
Vous pouvez également envisager de nommer ce ToEnum <> (), car il vient après l'objet.
Neil
Notez que Enum.TryParse <T> a été ajouté à Net 4.0 - blogs.msdn.com/bclteam
Dan Diplo
1
Je ne pense pas que cette méthode devrait utiliser Trim. Le découpage de l'entrée devrait être la responsabilité de l'appelant.
CodesInChaos
32

Je trouve celui-ci assez utile:

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

Vous pouvez l'utiliser sur CodePlex.

Juliette
la source
2
Quelqu'un peut-il avoir la gentillesse de l'expliquer aux moins doués d'entre nous?
jpbochi
hahaha Il suffit de lire l'article (commentaire de Joel ci-dessus) - drôle vrai, mais ayant été à peu près dans le même bateau (côté réception, pas côté Paula), ce n'est que drôle en regardant en arrière! Une fois, un entrepreneur a été amené à travailler sur un projet, j'étais designer / développeur principal - elle n'était pas sous mon contrôle direct, mais on m'a assigné du travail à partir de la liste de travail de mes équipes. Les patrons l'ont saluée comme étant brillante (même en l'embauchant à nouveau plus tard en tant que responsable du développement!). Il ne leur est jamais venu à l'esprit que chaque morceau de code qu'elle avait écrit ou conçu n'était pas parvenu à la production et que tout devait être entièrement réécrit à partir de zéro par mon équipe!
Wolf5370
31

DateTimeExtensions

Exemples:

DateTime firstDayOfMonth = DateTime.Now.First();
DateTime lastdayOfMonth = DateTime.Now.Last();
DateTime lastFridayInMonth = DateTime.Now.Last(DayOfWeek.Friday);
DateTime nextFriday = DateTime.Now.Next(DayOfWeek.Friday);
DateTime lunchTime = DateTime.Now.SetTime(11, 30);
DateTime noonOnFriday = DateTime.Now.Next(DayOfWeek.Friday).Noon();
DateTime secondMondayOfMonth = DateTime.Now.First(DayOfWeek.Monday).Next(DayOfWeek.Monday).Midnight();
CMS
la source
5
Je suggère de renommer "SetTime" en "WithTime" car il ne le définit pas réellement dans la valeur existante. Bien sinon.
Jon Skeet
28
DateTime.Now.First () - d'abord quoi? Cela n'apparaît que dans l'exemple de code.
mackenir
2
Très agréable. Mais convenez que les noms pourraient être bien meilleurs.
bovium
DateTime.Now.First sera suffisamment clair dans Intellisense si la méthode est bien documentée.
Ryan Lundy
29

gitorious.org/cadenza est une bibliothèque complète de certaines des méthodes d'extension les plus utiles que j'ai vues.

sontek
la source
12 méthodes d'extension assez basiques. Je suis un peu déçu par les mono-roches.
mackenir
(Je parle de la version publiée, pas celle dont vous avez besoin pour utiliser le contrôle de source)
mackenir
28

En voici un que j'utilise fréquemment pour le formatage des présentations.

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

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

    // TextInfo.ToTitleCase only operates on the string if is all lower case, otherwise it returns the string unchanged.
    return textInfo.ToTitleCase(mText.ToLower());
}
Venr
la source
Whoah, la gestion des exceptions Pokemon va cacher des problèmes comme ThreadAbortException, etc. Veuillez attraper quelque chose de spécifique.
JBRWilkinson
28

Voici un va-et-vient pour les chiffres romains. Pas souvent utilisé, mais pourrait être utile. Usage:

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

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

La source:

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

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

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

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

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

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

            var length = value.Length;

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

            var total = 0;
            var i = length;

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

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

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

                total += digit;
            }

            return total;
        }

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

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

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

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

            return sb.ToString();
        }
    }
Jesse C. Slicer
la source
Cela me rappelle le PEP Python 313, ce qui était une blague Fools Avril pour inclure littéraux Roman numéral en python: python.org/dev/peps/pep-0313
riale
25

Un moyen pratique de gérer les tailles:

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

public class Program {
    public void Main() {
        WSHttpContextBinding serviceMultipleTokenBinding = new WSHttpContextBinding() {
            MaxBufferPoolSize = 2.M(), // instead of 2097152
            MaxReceivedMessageSize = 64.K(), // instead of 65536
        };
    }
}
Paolo Tedesco
la source
À mon avis, c'est vraiment un mauvais style de codage. Les constantes doivent être utilisées à la place, et non la logique obscurcie.
xxbbcc
24

Pour les contrôles 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));
}

Utilisation d'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
    }
}

Utilisation de SetDropdownWidth:

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

J'ai oublié de mentionner, n'hésitez pas à les utiliser sur Codeplex ...

fre0n
la source
1
Comme mentionné, c'est uniquement pour WinForms. Cela peut fonctionner avec WPF mais il y a des problèmes (décrits dans le commentaire sur WPF à msdn.microsoft.com/en-us/library/… ). La meilleure solution pour WPF que j'ai trouvée est décrite dans geekswithblogs.net/lbugnion/archive/2009/09/05/… (cependant, comme c'est une propriété statique, elle ne fonctionne pas vraiment comme méthode d'extension.)
scobi
23

Le ThrowIfArgumentIsNull est un bon moyen de faire cette vérification nulle que nous devrions tous faire.

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

Vous trouverez ci-dessous la façon de l'utiliser et cela fonctionne sur toutes les classes de votre espace de noms ou partout où vous utilisez l'espace de noms à l'intérieur.

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

Il est correct d'utiliser ce code sur le projet CodePlex .

bovium
la source
J'aime ça aussi, Jon l'a dans le sien, et j'utilise quelque chose de similaire d'Umbrella, pourrait supporter de laisser tomber la partie "ArgumentIs".
cfeduke
Ouais! c'est aussi une méthode d'extension kewl :)
Pure.Krome
3
Si vous utilisez le constructeur ArgumentNullException avec seulement 1 argument de chaîne, cet argument doit être uniquement le nom du paramètre et non le message d'erreur. Donc, votre code devrait ressembler à ceci: if (obj == null) throw new ArgumentNullException (parameterName);
Tommy Carlier
J'utiliserais default(T)pour cela et supprimerais l'exigence de classe.
Joel Coehoorn
1
@Joel: Les valeurs non par défaut pour les types natifs sont des arguments légitimes plus souvent que les valeurs nulles. La vérification par rapport à null est plus logique pour moi que la vérification par défaut. Bien sûr, je généralise l'idée en disant Require.ThatArgument(input != null)ou Require.ThatArgument(personId > 0). Il ne prend pas beaucoup plus de code, il est beaucoup plus flexible et il se lit bien. J'ai des remplacements supplémentaires qui prennent des fonctions lorsque vous souhaitez personnaliser le message d'erreur ou l'exception elle-même.
StriplingWarrior
22

Je manque l' instruction With de Visual Basic lors du passage à C #, alors voici:

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

Et voici comment l'utiliser en C #:

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

Économise beaucoup de frappe!

Comparez cela à:

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

mettre en projet codeplex

chakrit
la source
4
Juste une supposition, mais pensez à ce qui se passe si votre T est une structure.
Rauhotz
5
J'utilise également la syntaxe d'initialisation de la propriété c # 3.0 dans la mesure du possible pour obtenir le même résultat.
Steve
3
@chakrit, voici un exemple. Elle ne s'applique que lors de la création de l'objet Button n = new Button {Name = "Button1", Width = 100, Height = 20, Enabled = true};
Steve
1
Cela serait utile lorsque vous avez beaucoup d'événements à connecter, car la syntaxe d'initialisation des propriétés de C # ne prend pas en charge les événements.
Gabe
1
cela est également utile en dehors des initialiseurs de propriété, car vous ne pouvez les utiliser que lors de la création d'un nouvel objet. cette extension peut fonctionner sur des objets créés précédemment.
Brady Moritz
18

Prend un camelCaseWord ou PascalCaseWord et le "wordifie", c'est-à-dire 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])" ) );
}

Je l'utilise souvent en conjonction avec Capitalize

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

Exemple d'utilisation

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

Libre d'utiliser dans le projet codeplex

µBio
la source
L'agrégat dans Capitalize est assez mauvais pour les performances, car il crée de nombreuses instances de chaîne. Pourquoi ne pas utiliser word.Substring (1) à la place?
Thomas Levesque
17

J'ai trouvé celui-ci utile

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

Il supprime la vérification nulle dans le code appelant. Vous pouvez maintenant faire

MyList.EmptyIfNull().Where(....)
Vasu Balakrishnan
la source
Oui, si quelqu'un a oublié "Null Object Pattern", cette méthode est utile pour le patcher. La collection ne doit jamais être nulle.
Pavel Hodek
16

Convertissez un double en chaîne formatée à l'aide de la culture spécifiée:

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

Exemple:

double test = 154.20;
string testString = test.ToCurrency("en-US"); // $154.20
CMS
la source
13
Vous devriez utiliser Decimal pour les autres devises, vous aurez des problèmes d'arrondi
Andrew Bullock
Qu'en est-il de l'utilisation d'une énumération dans le paramètre au lieu d'une chaîne ordinaire
Rulas
15

Vous trouverez ci-dessous une méthode d'extension qui adapte le code de Rick Strahl (et les commentaires aussi) pour vous éviter d'avoir à deviner ou à lire la marque d'ordre des octets d'un tableau d'octets ou d'un fichier texte à chaque fois que vous le convertissez en chaîne.

L'extrait vous permet de faire simplement:

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

Si vous trouvez des bogues, veuillez ajouter aux commentaires. N'hésitez pas à l'inclure dans le projet Codeplex.

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

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

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

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

        using (MemoryStream stream = new MemoryStream())
        {
            stream.Write(buffer, 0, buffer.Length);
            stream.Seek(0, SeekOrigin.Begin);
            using (StreamReader reader = new StreamReader(stream, encoding))
            {
                return reader.ReadToEnd();
            }
        }
    }
}
Chris S
la source
Méthode très utile, mais je ne pense pas qu'elle devrait l'être et méthode d'extension.
Pop Catalin
Si vous écrivez un éditeur de texte, cela justifie probablement une méthode d'extension, mais je suis d'accord la plupart du temps, ce n'est probablement rien de plus qu'une méthode privée statique
Chris S
15

En voici une que je viens de créer aujourd'hui.

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

Il vous permet de faire ceci:

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

qui est plus fluide et (OMI) plus lisible que cela:

var lname = (thingy != null ? thingy.Name : null) != null
    ? thingy.Name.ToLower() : null;
Scott Bilas
la source
1
Et si je veux thingy.NullOr(t => t.Count), où Countest un int? Vous devriez retourner default(TReturn)plutôt que null, de cette façon, vous n'aurez pas besoin de la classcontrainte et cela fonctionnera également pour les types de valeur
Thomas Levesque
2
TIn doit être une classe, sinon toute cette méthode d'extension n'a aucun sens (les types de valeur ne peuvent pas être nuls). Et votre exemple avec t.Count fonctionne avec la méthode d'extension ci-dessus. Pourriez-vous jeter un deuxième coup d'œil?
scobi
@Scott: c'est une méthode utile pour résoudre un problème commun. Cependant, je crois TReturn elseValue = default(TReturn)que n'est disponible que pour .NET 4.0? J'ai 3.5 SP1 et je n'ai jamais vu cette construction (ni mon compilateur). Je viens de déplacer cela à l'intérieur de la méthode. Un problème, cependant, est que la mise en boîte d'un type nullable à un objet à utiliser avec la méthode donne un résultat inattendu (0 par rapport à null attendu).
Jim Schubert
@Jim: le default(T)mot - clé existe depuis VS2005, mais je pense que les paramètres par défaut sont une nouvelle fonctionnalité .NET 4. Le moyen le plus simple devrait être d'avoir deux variantes, une qui prend le param et l'autre qui ne le fait pas. Je mettrai à jour la réponse pour être compatible CLR 2.0. En ce qui concerne la boxe - c'est le but de default. Il s'agira de données initialisées à 0 pour un type de valeur et null pour tous les types de référence. Un TReturn d'un type de valeur doit rester non encadré tout au long de la fonction.
scobi
@Scott: Ma question portait sur le paramètre par défaut, que je n'ai vu que dans des langages dynamiques comme Ruby. Mon point concernant les types nullables est que le retour x.Valuedoit retourner null (si, par exemple, int?était nul) ou la valeur if int?a une valeur. Retourner 0quand int? x = nullest passé et encadré à l'objet est un cas étrange. J'ai vu des vérifications similaires pour les types nullables dans des bibliothèques telles que fluent nhibernate et linfu (je pense) pour ce cas spécifique, vous permettant de supprimer la contrainte de classe comme suggéré précédemment.
Jim Schubert
14

"Veuillez marquer vos réponses avec une acceptation pour mettre le code dans le projet Codeplex."

Pourquoi? Tous les trucs sur ce site sous CC-by-sa-2.5 , alors mettez simplement votre projet de débordement d'extension sous la même licence et vous pouvez l'utiliser librement.

Quoi qu'il en soit, voici une fonction String.Reverse, basée sur cette question .

/// <summary>
/// Reverse a String
/// </summary>
/// <param name="input">The string to Reverse</param>
/// <returns>The reversed String</returns>
public static string Reverse(this string input)
{
    char[] array = input.ToCharArray();
    Array.Reverse(array);
    return new string(array);
}
Michael Stum
la source
String n'implémente-t-il pas déjà IEnumerable <char>? Il vous suffit donc de renvoyer une nouvelle chaîne (input.Reverse ());
Iain Galloway
Une implémentation utilisant StringBuilder devrait être plus rapide.
CodesInChaos
1
@CodeInChaos L'analyse comparative dans stackoverflow.com/questions/228038 a mesuré que StringBuilder est plus lent.
Michael Stum
Tu as raison. Il semble que les exigences de sécurité des threads (probablement pour garantir l'immuabilité de la chaîne renvoyée par ToString) ralentissent beaucoup StringBuilder.
CodesInChaos
2
J'espère que vous ne rencontrerez pas de substituts ou de combinaison de personnages.
dalle
14

Je me suis fatigué de la vérification nulle fastidieuse lors de l'extraction des valeurs de MySqlDataReader, donc:

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

Bien sûr, cela pourrait être utilisé avec n'importe quel SqlDataReader.


Hangy et Joe ont tous deux fait de bons commentaires sur la façon de procéder, et j'ai depuis eu l'occasion d'implémenter quelque chose de similaire dans un contexte différent, alors voici une autre 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);
}
Adam Lassek
la source
2
Cela devrait également fonctionner comme une méthode d'extension pour IDataReader.
hangy
2
Effectuez en fait le paramètre "this" de type IDataRecord pour une compatibilité maximale. Dans ma version de ceci, j'ai une surcharge qui prend un ordinal, que la version fieldName appelle. Enregistre le "GetOrdinal" suivi d'une recherche par nom.
Joel Mueller
Il existe une implémentation appropriée, qui peut gérer tout type de valeur: rabdullin.com/journal/2008/12/6/…
Rinat Abdullin
Merci Rinat, je l'ai en fait réduit à une seule méthode générique - voir stackoverflow.com/questions/303287
Adam Lassek
Toutes ces méthodes semblent inutiles car vous pouvez utiliser le asmot - clé pour obtenir une valeur d'un lecteur permettant null. Si vous combinez l' ??opérateur de coalescence nul avec l'opérateur as, vous pouvez même avoir une valeur par défaut non nulle pour accéder directement à un type de valeur. Voir stackoverflow.com/questions/746767/…
stevehipwell
14

Cela m'a énervé que LINQ me donne un OrderBy qui prend une classe implémentant IComparer comme argument, mais ne prend pas en charge la transmission d'une simple fonction de comparaison anonyme. J'ai rectifié cela.

Cette classe crée un IComparer à partir de votre fonction de comparaison ...

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

... et ces méthodes d'extension exposent mes nouvelles surcharges OrderBy sur les énumérateurs. Je doute que cela fonctionne pour LINQ to SQL, mais c'est génial pour 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);
    }
}

Vous êtes invités à mettre cela sur codeplex si vous le souhaitez.

Joel Mueller
la source
13

Celui-ci est pour MVC, il ajoute la possibilité de générer une <label />balise à la Htmlvariable qui est disponible dans chaque ViewPage. J'espère que cela sera utile à d'autres qui essaient de développer des extensions similaires.

Utilisation:

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

Production:

<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);
    }
}
tours16
la source
Découvrez MvcContrib.FluentHtml
Arnis Lapsa
Cela devrait probablement être dupliqué avec Literal à la place.
Mark Hurd du
12

Tournez ceci:

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

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

command.Parameters.Add(param);

... dans ceci:

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

... en utilisant cette méthode d'extension:

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

Autres méthodes d'extension ADO.NET: DbExtensions

Max Toro
la source