Jakie są twoje ulubione metody rozszerzenia dla C #? (codeplex.com/extensionoverflow)


478

Zróbmy listę odpowiedzi, w której zamieścisz swoje doskonałe i ulubione metody rozszerzenia .

Wymagane jest opublikowanie pełnego kodu oraz przykładu i wyjaśnienia, jak go używać.

W związku z dużym zainteresowaniem tym tematem skonfigurowałem projekt Open Source o nazwie Extensionoverflow na Codeplex .

Proszę zaznaczyć swoje odpowiedzi akceptacją umieszczenia kodu w projekcie Codeplex.

Proszę zamieścić pełny kod źródłowy, a nie link.

Wiadomości Codeplex:

24.08.2010 Strona Codeplex jest już tutaj: http://extensionoverflow.codeplex.com/

11.11.2008 XmlSerialize / XmlDeserialize jest teraz zaimplementowany i przetestowany jednostkowo .

11.11.2008 Jest jeszcze miejsce dla większej liczby programistów. ;-) Dołącz TERAZ!

11.11.2008 Trzeci współtwórca dołączył do ExtensionOverflow , witamy w BKristensen

11.11.2008 FormatWith jest teraz zaimplementowany i przetestowany jednostkowo .

09.11.2008 Drugi współtwórca dołączył ExtensionOverflow . witamy w czakrycie .

09.11.2008 Potrzebujemy więcej programistów. ;-)

09.11.2008 ThrowIfArgumentIsNull jest już zaimplementowany i przetestowany w Codeplex.


Teraz pierwszy kod jest przypisany do strony Codeplex.
bovium

Erik niestety wszystko zaczęło się teraz na codeplex. Dołącz mimo to.
bovium,

3
Wygląda całkiem nieźle. Mam komentarz na temat nazywania klas statycznych. Nazywanie ich <typem> Rozszerzenia nie jest zbyt pouczające. Na przykład StringExtensions zawiera zarówno formatowanie, jak i xml. Myślę, że lepiej nazwać klasę tym, dlaczego rozszerzasz ten typ. Na przykład UnixDateTimeConversions. Można rozsądnie zgadywać, że zawiera metody konwersji do i od czasu uniksowego. Tylko myśl!
ecoffey

Sprawdź ten adres URL, aby uzyskać więcej informacji na temat metod rozszerzenia C # planetofcoders.com/c-extension-methods
Gaurav Agrawal

Odpowiedzi:


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

Pozwala mi wymienić:

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

Z:

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
Kompiluje się, jeśli używasz System.Linq;
Ryu,

11
Może „EqualsAnyOf” byłoby lepszą nazwą niż „In”?
Tom Bushell,

10
Nie jestem pewien, czy mi się podoba - lubię zwięzłość In, ale może IsInbyłoby lepiej.
Winston Smith,

50
Przy użyciu tej samej metody Contains: (new [] {1, 2, 3}). Contains (a)
Max Toro

4
Pomyślałem o In<T>(...)tym i uznałem, że jest to najbardziej użyteczna metoda rozszerzenia poza standardową biblioteką. Ale nie zgadzam się z tym imieniem In. Nazwa metody powinna opisywać, co robi, ale Intego nie robi. Nazwałem to IsAnyOf<T>(...), ale myślę, że IsIn<T>(...)byłoby to również odpowiednie.
JBSnorro,

160

Mam różne metody rozszerzenia w moim projekcie MiscUtil (dostępne jest tam pełne źródło - nie zamierzam go tutaj powtarzać). Moje ulubione, z których niektóre obejmują inne klasy (takie jak zakresy):

Data i godzina - głównie do testów jednostkowych. Nie jestem pewien, czy użyję ich w produkcji :)

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

Zakresy i wchodzenie - ogromne dzięki Marcowi Gravellowi za rzeczy operatora, aby było to możliwe:

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

Porównania:

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

Sprawdzanie argumentów:

x.ThrowIfNull("x");

LINQ to XML zastosowane do typów anonimowych (lub innych typów o odpowiednich właściwościach):

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

Wciśnij LINQ - wyjaśnienie tutaj zajęłoby zbyt dużo czasu, ale poszukaj go.


1
To miłe! Powinieneś opublikować go na Google Code lub CodePlex, abym mógł wysłać ci kilka poprawek :-) Obiecuję, że będzie czytelny :-P
chakrit

3
@bovium: Możesz już zobaczyć kod. Kliknij link w pierwszym zdaniu - dostępne jest pełne źródło.
Jon Skeet,

1
@bovium: Wolę zrobić to sam, umieszczając go na code.google.com i sam zarządzając projektem, jeśli nie masz nic przeciwko. Oczywiście masz licencję na umieszczenie go w Codeplex, jeśli zachowasz odpowiednią atrybucję, ale wolę sam to rozwiązać, chyba że jesteś zdesperowany :)
Jon Skeet

1
@Jon Skeet. Jest objęty licencją MIT i jest bezpłatny dla wszystkich. Handlowo lub open source. Dlaczego nie połączyć sił i stworzyć publicznie bibliotekę metod rozszerzeń.
bovium

1
Tylko dlatego, że robię wiele innych elementów w tej bibliotece. Możesz wziąć kopię tego wszystkiego dla swojego projektu, ale wolałbym zachować jedną kopię w moim własnym projekcie.
Jon Skeet,

147

string.Format skrót:

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

Przykład:

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

Aby szybko skopiować i wkleić, przejdź tutaj .

Czy nie uważasz, że bardziej naturalne jest pisanie "some string".F("param")zamiast string.Format("some string", "param")?

Aby uzyskać bardziej czytelną nazwę, wypróbuj jedną z następujących sugestii:

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
Z pewnością jest krótki - ale będzie nieczytelny dla nowych członków Twojego zespołu.
Jon Skeet,

3
Myślę, że czytelność ma większe znaczenie w większym schemacie kodu niż kilka krótkich instrukcji, które można szybko sprawdzić / zapytać.
chakrit

6
Osobiście chciałbym osobny obiekt Formatter, który BCL mógłby raz przeanalizować wzorzec i użyć ponownie. Zwiększyłoby to czytelność i wydajność. Zapytałem zespół BCL - zobaczymy ...
Jon Skeet

3
Jest to metoda rozszerzenia, oczywiście będzie ona nieczytelna dla nowych członków zespołu. Myślałem, że taki był pomysł z tymi dowcipnymi rzeczami? Jak inaczej nowi członkowie będą wiedzieć, jak sprytni jesteśmy?
MarkJ

17
Ok ... Właśnie poszedłem wprowadzić to w życie i poszedłem z .Z - więc dostajesz „To jest {0}”. Z („test”) i jest bardzo czytelne i ma sens. FYI
klkitchens

89

Czy to jakiś użytek?

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

naśladuje funkcję random.choice (seq) w pythonach. miły.
Daren Thomas,

6
Kilka rzeczy: polecam, że OneOfpowinienem zaakceptować każdy IList<T> . Wtedy zawsze można też mieć przeciążenie, że trwa paramsArg i właśnie przechodzi że do IList<T>przeciążenia. Odpowiedziałem (teraz na dole u dołu) NextBoolmetodą podobną do twojej CoinToss, ale z przeciążeniem, które przyjmuje probabilityparametr (co jeśli chcę, żeby coś się wydarzyło 75% czasu?). Ponadto, wystarczy wybrać nit: twój przykładowy kod wyrzuci, NullReferenceExceptionponieważ randnigdy nie jest inicjowany.
Dan Tao

3
+1 Naprawdę podoba mi się to, ale wolę CoinTossbyć zaimplementowany, rng.NextDouble() < .5ponieważ .Next(int)jest wewnętrznie wykonany .NextDouble(), abyś mógł zapisać rzut, * i czek.
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;
  }
}

Przykład:

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

19
Uwielbiam ten, ale staram się zdecydować, czy należy sprawdzić granice łącznie z wartością minimalną, ale wyłączną z wartości maksymalnej. Zastanawiam się, czy byłoby to mylące. 5. Pomiędzy (5,10) jest prawdą, ale 5. Między (1,5) jest fałszywy. Nie jestem nawet pewien, czy pomogłaby w tym metoda towarzysząca. Myślisz?
Steve Hiner,

12
Czy nazwa „IsBetween” nie miałaby większego sensu? Może także zrobić IsBetweenInclusive i IsBetweenExclusive. Nie mam jednak pojęcia, który wybrać jako domyślny.
fretje

2
@ Steve: bardziej sensowne byłoby rozszerzenie daty i godziny.
Joel Coehoorn

16
Dla mnie między implikuje: 5. Pomiędzy (5,10) zwraca wartość false, a 10. Pomiędzy (5,10) również zwraca wartość false. To po prostu wydaje mi się naturalne.
Alex Baranosky,

3
Wydaje mi się, że wiele osób ma różne pomysły na to, co naturalne. Z tego powodu prawdopodobnie powinno być wyraźnie określone, co jest używane (tj. Włączenie vs Wyłącznie), ponieważ może to być bardzo łatwe źródło błędów.
David Miani,

58

Metoda rozszerzenia:

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

Metoda ma zastosowanie do wszystkich typów i pozwala dodawać zakres elementów do listy jako parametry.

Przykład:

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

15
Byłoby lepiej, ponieważ ta IList <T>

21
Wystarczy użyć inicjatora kolekcji =>var list = new List<int>{5,4,8,4,2};
Arnis Lapsa

Dlaczego po prostu nie wywołać List <T> .AddRange (kolekcja IEnumerable <T>) w ramach Twojej metody?
Rauhotz

8
@Will: Właściwie najlepiej byłoby zaakceptować ICollection<T>; wtedy można go również wykorzystać na przykład, LinkedList<T>a HashSet<T>nie tylko w indeksowanych kolekcjach.
Dan Tao

2
Edytowano, aby umożliwić kowariancję w wersji sprzed.net 4.0
BlueRaja - Danny Pflughoeft

55

Jak najbardziej, umieść to w projekcie codeplex.

Serializacja / deserializacja obiektów do XML:

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

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

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

    var serializer = new XmlSerializer(typeof(T));
    using (var reader = new StringReader(xml))
    {
        try { return (T)serializer.Deserialize(reader); }
        catch { return null; } // Could not be deserialized to this type.
    }
}

8
Chciałbym zadzwonić do pierwszego ToXml()(jak ToString())
Jay Bazuzi

1
Przepraszamy OP, jeśli celowo napisał to w ten sposób, ale użycie MemoryStreams AND XmlReader / XmlWriter było przesadą. Klasa StringReader i StringWriter są idealne do tej operacji.
Portman

2
Uwaga, to nie jest bezpieczne dla wątków. Zdecydowanie powinieneś zsynchronizować dostęp do statycznego słownika serializatorów.
Yann Schwartz

2
@Yann, @T, Łatwiej jest dodać atrybut „static static”. Następnie dla każdego wątku zostanie utworzona nowa pamięć podręczna. Nie ma potrzeby synchronizacji.
Frank Krueger,

1
@Jathanathan C Dickinson: Z dokumentów MSDN wynika, że ​​tutaj msdn.microsoft.com/en-us/library/... że używany konstruktor (nowy XmlSerializer (typ)) nie ma problemu z wyciekiem pamięci. Więc może kod buforowania nie jest potrzebny?
slolife

46

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

Naiwny przykład:

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

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

Fajny przykład:

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

Uwaga:

To nie jest tak, Selectponieważ się Select spodziewa że funkcja zwróci coś, jak w przypadku przekształcenia w inną listę.

ForEach pozwala po prostu wykonać coś dla każdego elementu bez żadnych transformacji / manipulacji danymi.

Zrobiłem to, aby móc programować w bardziej funkcjonalnym stylu i byłem zaskoczony, że List ma ForEach, podczas gdy IEnumerable nie.

Umieść to w projekcie codeplex


13
Napisz, dlaczego rozszerzenia IET dla LINQ <T> nie zawierają ForEach: stackoverflow.com/questions/317874/...
Neil

13
Polecam przeczytać to przed użyciem metody: blogs.msdn.com/ericlippert/archive/2009/05/18/…
jpbochi

2
@jpbochi: To jest właśnie demagogia Microsoft
abatishchev

1
@abatishchev A twój komentarz jest tylko uprzedzeniem wobec Microsoft. Nie unieważnia żadnego słowa napisanego przez Erica. Czyjeś argumenty nie są ważne ani nieważne tylko z powodu firmy, dla której pracuje.
jpbochi

1
Przy okazji, pozwolę sobie wyjaśnić jedną kwestię. Nie powiedziałem, że nie powinieneś używać tej metody rozszerzenia ForEach. Właśnie powiedziałem, że powinieneś rozważyć punkty, które ujawnił Eric, zanim zdecydujesz, czy z niego skorzystać, czy nie. Przeczytałem go i postanowiłem go nie używać. Możesz robić, co tylko chcesz z kodem.
jpbochi

43

Moje rozszerzenia konwersji, które pozwalają:

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

Oto, jak opublikowano na 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;
    }
}

Możesz poprosić o wartość domyślną (wywołuje pusty konstruktor lub „0” dla liczb) w przypadku niepowodzenia, możesz podać wartość „domyślną” (nazywam to „inną”) lub poprosić o wartość null (gdzie T: klasa). Podałem również oba ciche modele wyjątków oraz typowy model TryParse, który zwraca wartość bool wskazującą na podjęte działanie, a parametr wyjściowy zawiera nową wartość. Więc nasz kod może robić takie rzeczy

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

Nie mogłem zmusić typów Nullable do bardzo czystego wtoczenia się w całość. Próbowałem przez około 20 minut, zanim rzuciłem ręcznik.


64
Osobiście nie jestem fanem kodu, który próbuje / łapie w celu ustalenia wyniku. Try / catch należy stosować w przypadku błędów, które występują poza zamierzoną logiką IMO. hmmmmm
Pure.Krome

Gdybym nie chciał, żebyś używał kodu, nie opublikowałbym go! :)
TheSoftwareJedi

Wreszcie coś niewidzialnego. Lubię to. :)
Arnis Lapsa

8
Powinieneś przynajmniej zmienić tę klauzulę „catch”, aby wychwycić tylko te wyjątki, które zostanie zgłoszone przez ChangeType (), gdy nie będzie w stanie „przekonwertować” referencji. Myślę, że nie chciałbyś, aby jakikolwiek błąd OutOfMemoryException, ExecutionEngineException, ThreadAbortException lub podobny był traktowany jako błąd konwersji. W przeciwnym razie śledzenie błędów będzie trudne.
Christian.K,

2
Uważam, że ToOrNullma dokładnie takie samo zachowanie jak ToOrDefault(tzn. Jeśli wywołasz ToOrDefaulttyp referencyjny z nieudaną konwersją, zwróci null). Ale co ważniejsze, wydaje mi się to trochę zbędne, ponieważ var s = myObject as stringosiąga to samo, co var s = myObject.ToOrNull<string>()- ale bez potencjalnej konieczności złapania InvalidCastException. Czy coś brakuje?
Dan Tao

43

Mam metodę rozszerzenia do rejestrowania wyjątków:

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

I jest używany w następujący sposób:

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

[przepraszam, że wysłałem dwa razy; drugi jest lepiej zaprojektowany :-)]


2
Czy powinienem przeczytać publiczny statyczny void Log (ten wyjątek obj) {}?
Chris S

Myślę, że jest to dobre dla wyjątków BCL lub innych firm, ale jeśli wprowadzisz własne typy wyjątków, możesz umieścić rejestrowanie w swojej podstawowej klasie wyjątków. W ten sposób nie musisz pamiętać, aby wywoływać 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);
    }
}

Przydatne do parsowania łańcucha w Enum.

public enum TestEnum
{
    Bar,
    Test
}

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

Zasługa Scott Dorman

--- Edycja dla projektu Codeplex ---

Zapytałem Scotta Dormana, czy miałby coś przeciwko, abyśmy opublikowali jego kod w projekcie Codeplex. Oto odpowiedź, którą od niego otrzymałem:

Dzięki za informacje na temat zarówno postu SO, jak i projektu CodePlex. Poparłem twoją odpowiedź na pytanie. Tak, kod znajduje się w domenie publicznej obecnie na podstawie licencji CodeProject Open License ( http://www.codeproject.com/info/cpol10.aspx ).

Nie mam problemów z włączeniem tego do projektu CodePlex, a jeśli chcesz mnie dodać do projektu (nazwa użytkownika to sdorman), dodam tę metodę oraz kilka dodatkowych metod pomocniczych enum.


Cały ten scenariusz analizowania
enumu

Wow, piszę metody mapowania ciągów znaków na wyliczenia (właśnie zacząłem używać .NET). Dzięki, to absolutnie pomoże!
Kevin,

4
Możesz również rozważyć nazywanie tego ToEnum <> (), ponieważ występuje on po obiekcie.
Neil

Zauważ, że Enum.TryParse <T> został dodany do Net 4.0 - blogs.msdn.com/bclteam
Dan Diplo

1
Nie sądzę, że ta metoda powinna używać Trim. Za przycięcie wejścia powinien odpowiadać dzwoniący.
CodesInChaos

32

Uważam to za bardzo przydatne:

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

Możesz używać go w CodePlex.


2
Czy ktoś może być na tyle uprzejmy, aby wyjaśnić to mniej utalentowanemu z nas?
jpbochi

hahaha Wystarczy przeczytać artykuł (komentarz Joela powyżej) - zabawna prawda, ale będąc na tej samej łodzi (na końcu, a nie na końcu Pauli), to zabawne, patrząc wstecz! Kiedyś przyprowadzono wykonawcę do pracy nad projektem, nad którym pracowałem jako projektant / główny projektant - nie była pod moją bezpośrednią kontrolą, ale przydzielono jej pracę z listy prac moich zespołów. Szefowie chwalili ją za błyskotliwość (nawet zatrudniając ją ponownie jako Dev Lead!). Nigdy nie przyszło im do głowy, że każdy napisany lub zaprojektowany przez siebie fragment kodu nie trafił do produkcji i wszystko to musi zostać całkowicie przepisane przez mój zespół!
Wolf5370

31

DateTimeExtensions

Przykłady:

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
Proponuję zmienić nazwę „SetTime” na „WithTime”, ponieważ tak naprawdę nie ustawia go w istniejącej wartości. W przeciwnym razie miło.
Jon Skeet

28
DateTime.Now.First () - po pierwsze co? Jest to widoczne tylko z przykładowego kodu.
mackenir,

2
Bardzo dobrze. Ale zgódź się, że nazwy mogą być znacznie lepsze.
bovium

DateTime.Now.First będzie wystarczająco jasny w Intellisense, jeśli metoda jest dobrze udokumentowana.
Ryan Lundy,

29

gitorious.org/cadenza to pełna biblioteka jednych z najbardziej użytecznych metod rozszerzenia, jakie widziałem.


12 dość podstawowych metod rozszerzenia. Jestem trochę rozczarowany mono-skałami.
mackenir,

(Mówię o wydanej wersji, a nie tej, której potrzebujesz, aby uzyskać kontrolę nad źródłami)
mackenir,

28

Oto jeden, którego często używam do formatowania prezentacji.

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, obsługa wyjątków Pokemon ukryje problemy takie jak ThreadAbortException itp. Proszę złapać coś konkretnego.
JBRWilkinson

28

Oto cyfry rzymskie. Nie jest często używany, ale może być przydatny. Stosowanie:

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

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

Źródło:

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

To mi przypomina pytona PEP 313, który był żart Prima Aprilis zawierać rzymska literały w Pythonie: python.org/dev/peps/pep-0313
torialnego

25

Wygodny sposób radzenia sobie z rozmiarami:

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

Moim zdaniem jest to naprawdę kiepski styl kodowania. Zamiast tego należy stosować stałe, a nie zaciemnioną logikę.
xxbbcc,

24

W przypadku formantów 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));
}

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

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

Zapomniałem wspomnieć, możesz użyć ich na Codeplex ...


1
Jak wspomniano, dotyczy to tylko WinForm. Może działać z WPF, ale występują problemy (opisane w komentarzu na temat WPF na msdn.microsoft.com/en-us/library/… ). Najlepsze rozwiązanie dla WPF, które znalazłem, jest opisane w geekswithblogs.net/lbugnion/archive/2009/09/05/… (chociaż, ponieważ jest to właściwość statyczna, tak naprawdę nie działa jako metoda rozszerzenia.)
scobi

23

ThrowIfArgumentIsNull to dobry sposób na wykonanie kontroli zerowej, którą wszyscy powinniśmy zrobić.

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

Poniżej znajduje się sposób korzystania z niego i działa on na wszystkich klasach w Twojej przestrzeni nazw lub wszędzie tam, gdzie używasz przestrzeni nazw.

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

Można używać tego kodu w projekcie CodePlex .


Ja też to lubię, Jon ma to w sobie i używam czegoś podobnego z Umbrella, może znieść część „ArgumentIs”.
cfeduke

Tak! jest to również metoda rozszerzenia kewl :)
Pure.Krome

3
Jeśli używasz konstruktora wyjątków ArgumentNullException tylko z jednym argumentem-ciągiem, argumentem musi być tylko nazwa parametru, a nie komunikat o błędzie. Twój kod powinien więc wyglądać tak: if (obj == null) wyrzuć nowy ArgumentNullException (parameterName);
Tommy Carlier

Użyłbym default(T)tego i usunęł wymagania klasowe.
Joel Coehoorn

1
@Joel: Wartości inne niż domyślne dla typów rodzimych są uzasadnionymi argumentami częściej niż wartości zerowe. Sprawdzanie wartości zerowej ma dla mnie większy sens niż sprawdzanie wartości domyślnej. Oczywiście po prostu uogólniam cały pomysł, mówiąc Require.ThatArgument(input != null)lub Require.ThatArgument(personId > 0). Nie wymaga dużo więcej kodu, jest o wiele bardziej elastyczny i ładnie czyta. Mam dodatkowe przesłonięcia, które uwzględniają funkcje, gdy chcesz dostosować komunikat o błędzie lub sam wyjątek.
StriplingWarrior

22

Tęsknię za instrukcją With w języku Visual Basic przy przejściu do C #, więc oto:

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

A oto jak używać go w C #:

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

Oszczędza dużo pisania!

Porównaj to z:

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

umieścić w projekcie codeplex


4
Tylko zgadnij, ale zastanów się, co się stanie, jeśli Twój T jest strukturą.
Rauhotz

5
Tam, gdzie to możliwe, używam również składni inicjalizującej właściwości c # 3.0, aby osiągnąć ten sam wynik.
Steve

3
@chakrit, oto przykład. Ma zastosowanie tylko podczas tworzenia obiektu Przycisk n = nowy Przycisk {Nazwa = "Przycisk 1", Szerokość = 100, Wysokość = 20, Włączone = prawda};
Steve

1
Byłoby to przydatne, gdy masz wiele zdarzeń do podłączenia, ponieważ składnia inicjalizująca właściwość C # nie obsługuje zdarzeń.
Gabe

1
jest to również przydatne poza inicjalizatorami właściwości, ponieważ można ich używać tylko podczas tworzenia nowego obiektu. to rozszerzenie może działać na wcześniej utworzonych obiektach.
Brady Moritz

18

Pobiera camelCaseWord lub PascalCaseWord i „formułuje” go, tzn. CamelCaseWord => Słowo wielbłąda

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

Często używam go w połączeniu z Capitalize

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

Przykładowe użycie

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

Bezpłatnie korzystać z projektu codeplex


Agregacja w wielkich literach jest dość niekorzystna dla wydajności, ponieważ tworzy wiele instancji łańcuchów. Dlaczego zamiast tego nie użyć word.Substring (1)?
Thomas Levesque,

17

Uznałem to za pomocne

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

Usuwa zaznaczenie zerowe w kodzie wywołującym. Możesz teraz zrobić

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

Tak, jeśli ktoś zapomniał „Wzorzec zerowy obiektu”, ta metoda jest przydatna do jego załatania. Kolekcja nigdy nie powinna mieć wartości zerowej.
Pavel Hodek

16

Konwertuj podwójne na ciągi sformatowane przy użyciu określonej kultury:

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

Przykład:

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

13
W przypadku waluty należy użyć opcji Dziesiętny, w przeciwnym razie wystąpią problemy z zaokrąglaniem
Andrew Bullock,

Co powiesz na użycie Enum w parametrze zamiast zwykłego ciągu
Rulas

15

Poniżej znajduje się metoda rozszerzenia, która dostosowuje kod Ricka Strahla (i także komentarze), aby nie trzeba było zgadywać lub czytać znaku kolejności bajtów tablicy bajtów lub pliku tekstowego za każdym razem, gdy konwertujesz go na ciąg.

Fragment pozwala po prostu wykonać:

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

Jeśli znajdziesz jakieś błędy, dodaj je do komentarzy. Dołącz go do projektu 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();
            }
        }
    }
}

Bardzo przydatna metoda, ale nie sądzę, że powinna być i metoda rozszerzenia.
Pop Catalin

Jeśli piszesz edytor tekstów, prawdopodobnie uzasadnia to metodę rozszerzenia, ale zgadzam się, że w większości przypadków jest to tylko statyczna metoda prywatna
Chris S

15

Oto jeden, który właśnie stworzyłem dzisiaj.

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

Pozwala ci to zrobić:

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

który jest bardziej płynny i (IMO) łatwiejszy do odczytania niż to:

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

1
Co jeśli chcę thingy.NullOr(t => t.Count), gdzie Countjest int? Powinieneś powrócić default(TReturn)zamiast zerowego, w ten sposób nie będziesz potrzebować classograniczenia i będzie ono działać również dla typów wartości
Thomas Levesque,

2
TIn powinien być klasą, w przeciwnym razie cała metoda rozszerzenia nie ma sensu (typy wartości nie mogą mieć wartości null). Twój przykład z t.Count działa z powyższą metodą rozszerzenia. Czy możesz spojrzeć po raz drugi?
scobi

@ Scott: jest to przydatna metoda na typowy problem. Jednak uważam, że TReturn elseValue = default(TReturn)jest dostępny tylko dla .NET 4.0? Mam 3.5 SP1 i nigdy nie widziałem tej konstrukcji (nie ma też mojego kompilatora). Właśnie przeniosłem to do metody. Jednym z problemów jest jednak to, że umieszczenie w polu obiektu typu zerowalnego do obiektu w celu użycia z metodą daje nieoczekiwany wynik (0 w porównaniu z oczekiwanym zerowym).
Jim Schubert

@Jim: default(T)słowo kluczowe istnieje od VS2005, ale myślę, że domyślne parametry to nowa funkcja .NET 4. Łatwym rozwiązaniem powinno być posiadanie dwóch wariantów, jednego, który bierze param, a drugiego, który nie. Zaktualizuję odpowiedź, aby była zgodna z CLR 2.0. Jeśli chodzi o boks - o to właśnie chodzi default. Będą to dane inicjowane na 0 dla typu wartości, a null dla wszystkich typów referencji. TReturn typu wartości powinien pozostać rozpakowany przez całą funkcję.
scobi

@Scott: Moje pytanie dotyczyło domyślnego parametru, który widziałem tylko w dynamicznych językach, takich jak Ruby. Chodzi mi o typy zerowalne, że zwracanie x.Valuepowinno zwracać null (jeśli na przykład int?był null) lub wartość, jeśli int?ma wartość. Zwracanie 0po int? x = nullprzekazaniu i zapakowaniu do obiektu jest przypadkiem dziwnym. Widziałem podobne kontrole typów zerowalnych w bibliotekach, takich jak płynne nhibernate i linfu (tak myślę) w tym konkretnym przypadku, co pozwala na usunięcie ograniczenia klasy, jak wcześniej sugerowano.
Jim Schubert,

14

„Proszę zaznaczyć swoje odpowiedzi akceptacją, aby umieścić kod w projekcie Codeplex.”

Dlaczego? Wszystkie rzeczy na tej stronie pod CC-by-sa-2.5 , więc po prostu umieść swój projekt przepełnienia rozszerzenia na tej samej licencji i możesz go swobodnie używać.

Tak czy inaczej, tutaj jest funkcja String.Reverse, oparta na tym pytaniu .

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

Czy String nie implementuje już IEnumerable <char>? Musisz po prostu zwrócić nowy String (input.Reverse ());
Iain Galloway,

Implementacja przy użyciu StringBuilder powinna być szybsza.
CodesInChaos

1
@CodeInChaos Benchmarking w stackoverflow.com/questions/228038 zmierzył, że StringBuilder działa wolniej.
Michael Stum

Masz rację. Wygląda na to, że wymagania bezpieczeństwa wątków (prawdopodobnie w celu zapewnienia niezmienności ciągu zwracanego przez ToString) spowalniają StringBuilder.
CodesInChaos

2
Mam nadzieję, że nie spotkasz żadnych surogatów ani łączenia postaci.
dalle

14

Mam dość żmudnego sprawdzania wartości zerowej podczas pobierania wartości z MySqlDataReader, więc:

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

Oczywiście można tego użyć z dowolnym SqlDataReader.


Zarówno hangy, jak i Joe mieli dobre komentarze na temat tego, jak to zrobić, i od tego czasu miałem okazję zaimplementować coś podobnego w innym kontekście, więc oto inna wersja:

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
Powinno to również działać jako metoda rozszerzenia dla IDataReader.
hangy

2
W rzeczywistości ustaw parametr „this” typu IDataRecord, aby uzyskać maksymalną kompatybilność. W mojej wersji mam przeciążenie, które przyjmuje porządek, który wywołuje wersja fieldName. Zapisuje „GetOrdinal”, a następnie wyszukiwanie według nazwy.
Joel Mueller,

Istnieje właściwa implementacja, która może poradzić sobie z dowolnym typem wartości: rabdullin.com/journal/2008/12/6/…
Rinat Abdullin

Dzięki Rinat, mam jedną ogólną metodę - patrz stackoverflow.com/questions/303287
Adam Lassek

Wszystkie te metody wydają się niepotrzebne, ponieważ można użyć assłowa kluczowego, aby uzyskać wartość z czytnika, która pozwala na wartość null. Jeśli połączysz zerowy ??operator koalescencyjny z operatorem as, możesz nawet mieć inną niż zerową wartość domyślną, aby przejść bezpośrednio do typu wartości. Zobacz stackoverflow.com/questions/746767/…
stevehipwell

14

Zirytowało mnie, że LINQ daje mi OrderBy, który przyjmuje klasę implementującą IComparer jako argument, ale nie obsługuje przekazywania prostej anonimowej funkcji porównującej. Naprawiłem to.

Ta klasa tworzy IComparer z funkcji porównywania ...

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

... a te metody rozszerzeń ujawniają moje nowe przeciążenia OrderBy dla elementów wyliczeniowych. Wątpię, czy to działa w przypadku LINQ na SQL, ale świetnie nadaje się do LINQ na 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);
    }
}

Jeśli chcesz, możesz umieścić to w codeplex.


13

Ten jest dla MVC, dodaje możliwość generowania <label />znacznika do Htmlzmiennej, która jest dostępna w każdym ViewPage. Mamy nadzieję, że przyda się innym próbującym opracować podobne rozszerzenia.

Posługiwać się:

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

Wynik:

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

Kod:

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

Sprawdź MvcContrib.FluentHtml
Arnis Lapsa

Prawdopodobnie powinno się to powielić zamiast Dosłownie.
Mark Hurd

12

Włącz to:

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

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

command.Parameters.Add(param);

... zaangażowany w to:

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

... używając tej metody rozszerzenia:

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

Więcej metod rozszerzenia ADO.NET: DbExtensions

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.