วิธีการขยายที่คุณชื่นชอบสำหรับ C # คืออะไร? (codeplex.com/extensionoverflow)


478

มาทำรายการคำตอบที่คุณโพสต์วิธีการต่อยอดเยี่ยมและยอดนิยมวิธีการขยาย

ข้อกำหนดคือจะต้องโพสต์โค้ดแบบเต็มและตัวอย่างและคำอธิบายเกี่ยวกับวิธีใช้

ขึ้นอยู่กับดอกเบี้ยที่สูงในหัวข้อนี้ผมมีการติดตั้งโครงการที่มาเปิดที่เรียกว่า extensionoverflow ในCodeplex

โปรดทำเครื่องหมายคำตอบของคุณด้วยการยอมรับเพื่อใส่รหัสในโครงการ Codeplex

กรุณาโพสต์ซอร์สโค้ดแบบเต็มไม่ใช่ลิงก์

ข่าว Codeplex:

24.08.2010 หน้า Codeplex อยู่ที่นี่แล้ว: http://extensionoverflow.codeplex.com/

11.11.2008 XmlSerialize / XmlDeserializeถูกนำไปใช้งานและทดสอบหน่วยแล้วแล้ว

11.11.2008 ยังมีพื้นที่สำหรับนักพัฒนาเพิ่มเติม ;-) เข้าร่วมทันที!

11.11.2008 ผู้ควบคุมคนที่สามเข้าร่วมExtensionOverflowยินดีต้อนรับสู่BKristensen

11.11.2008 FormatWithขณะนี้มีการใช้งานและทดสอบหน่วยหน่วยทดสอบ

contributer 2008/11/09 สองเข้าร่วมExtensionOverflow ยินดีต้อนรับสู่chakritชาคริต

09.11.2008 เราต้องการนักพัฒนาเพิ่มเติม ;-)

09.11.2008 ThrowIfArgumentIsNullในตอนนี้ถูกนำไปใช้และยูนิตทดสอบบน Codeplex


ตอนนี้รหัสแรกมุ่งมั่นที่เว็บไซต์ Codeplex
bovium

เอริคน่าเสียดายที่ทุกอย่างเริ่มต้นที่ codeplex แล้ว กรุณาเข้าร่วม
bovium

3
ดูดีทีเดียว ฉันมีความคิดเห็นเกี่ยวกับการตั้งชื่อคลาสแบบคงที่ การตั้งชื่อให้พวกเขา <type> ส่วนขยายนั้นไม่มีข้อมูลมากนัก ตัวอย่างเช่น StringExtensions เก็บทั้งการจัดรูปแบบและสิ่ง xml ฉันคิดว่าเป็นการดีที่จะตั้งชื่อชั้นเรียนด้วยสาเหตุที่คุณขยายประเภทนั้น ตัวอย่างเช่น UnixDateTimeConversions คุณสามารถคาดเดาได้อย่างสมเหตุสมผลว่ามันมีวิธีการในการแปลงจาก Unix time แค่คิด!
ecoffey

ตรวจสอบ URL นี้เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีการขยาย C # planetofcoders.com/c-extension-methods
Gaurav Agrawal

คำตอบ:


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

อนุญาตให้ฉันแทนที่:

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

ด้วย:

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
มันจะรวบรวมถ้าคุณใช้ System.Linq;
Ryu

11
บางที "EqualsAnyOf" อาจเป็นชื่อที่ดีกว่า "In" ใช่ไหม
Tom Bushell

10
ฉันไม่แน่ใจว่าฉันชอบมัน - ฉันชอบความกะทัดรัดInแต่อาจIsInจะดีกว่า
Winston Smith

50
ใช้วิธีการเดียวกันประกอบด้วย: (ใหม่ [] {1, 2, 3}) มี (a)
Max Toro สูงสุด

4
ฉันคิดว่าIn<T>(...)เป็นอย่างดีและพบว่ามันเป็นวิธีการขยายที่มีประโยชน์มากที่สุดนอกห้องสมุดมาตรฐาน Inแต่ผมที่ขัดแย้งกับชื่อ ชื่อวิธีการนั้นควรจะอธิบายสิ่งที่มันทำ แต่Inไม่ได้ทำ ฉันเรียกมันIsAnyOf<T>(...)แล้ว แต่ฉันคิดว่าIsIn<T>(...)มันก็เพียงพอแล้วเช่นกัน
JBSnorro

160

ฉันมีวิธีการขยายต่าง ๆ ในโครงการMiscUtilของฉัน(มีซอร์สเต็มให้ - ฉันจะไม่ทำซ้ำที่นี่) รายการโปรดของฉันซึ่งบางส่วนเกี่ยวข้องกับชั้นเรียนอื่น ๆ (เช่นช่วง):

สิ่งที่วันที่และเวลา - ส่วนใหญ่สำหรับการทดสอบหน่วย ไม่แน่ใจว่าฉันจะใช้พวกเขาในการผลิต :)

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

ช่วงและก้าว - ขอบคุณมากสำหรับ Marc Gravell สำหรับผู้ปฏิบัติงานของเขาเพื่อให้สิ่งนี้เป็นไปได้:

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

เปรียบเทียบ:

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

ตรวจสอบข้อโต้แย้ง:

x.ThrowIfNull("x");

LINQ กับ XML ใช้กับประเภทที่ไม่ระบุตัวตน (หรือประเภทอื่น ๆ ที่มีคุณสมบัติที่เหมาะสม):

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

กด LINQ - ใช้เวลานานเกินไปในการอธิบายที่นี่ แต่ค้นหา


1
เยี่ยมมาก! คุณควรจะวางมันไว้บน Google Code หรือ CodePlex เพื่อที่ฉันจะได้ส่งแพตช์ให้คุณ :-) ฉันสัญญาว่ามันจะอ่านได้ :-P
chakrit

3
@bovium: คุณสามารถดูรหัสได้แล้ว ตามลิงค์ในประโยคแรก - มีแหล่งข้อมูลเต็ม
Jon Skeet

1
@bovium: ฉันควรทำด้วยตัวเองวางไว้บน code.google.com และจัดการโครงการด้วยตัวเองถ้าคุณไม่สนใจ เห็นได้ชัดว่าคุณอยู่ในใบอนุญาตให้ใส่ไว้ใน Codeplex ถ้าคุณให้ระบุแหล่งที่เหมาะสม แต่ฉันอยากจะจัดเรียงออกเองเร็ว ๆ นี้ถ้าคุณหมดหวัง :)
จอนสกีต

1
@ จอน Skeet มันอยู่ภายใต้ใบอนุญาต MIT ฟรีสำหรับทุกคน ในเชิงพาณิชย์หรือโอเพนซอร์ส ทำไมไม่เข้าร่วมกองกำลังและสร้างห้องสมุดวิธีการขยายสำหรับสาธารณะ
bovium

1
เพียงเพราะฉันทำบิตและชิ้นส่วนอื่น ๆ จำนวนมากในห้องสมุดนั้น คุณสามารถนำสำเนาทั้งหมดนี้ไปใช้ในโครงการของคุณ แต่ฉันอยากเก็บสำเนาไว้ในโครงการของฉันด้วย
Jon Skeet

147

string.Format ทางลัด:

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

ตัวอย่าง:

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

สำหรับการคัดลอกและวางอย่างรวดเร็วไปที่นี่ที่นี่

คุณไม่คิดว่ามันจะเป็นธรรมชาติหรือที่จะพิมพ์"some string".F("param")แทนที่จะเป็นstring.Format("some string", "param") ?

สำหรับชื่อที่อ่านได้มากขึ้นลองหนึ่งในข้อเสนอแนะเหล่านี้:

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
มันสั้นอย่างแน่นอน - แต่จะไม่สามารถอ่านได้สำหรับสมาชิกใหม่ในทีมของคุณ
Jon Skeet

3
ฉันคิดว่าการอ่านมีความสำคัญมากกว่าในโครงร่างโค้ดของคุณมากกว่าคำสั่งสั้น ๆ ที่สามารถค้นหา / ถามได้อย่างรวดเร็ว
chakrit

6
โดยส่วนตัวแล้วฉันต้องการวัตถุฟอร์แมตเตอร์แยกต่างหากซึ่ง BCL สามารถแยกวิเคราะห์รูปแบบของครั้งเดียวแล้วนำมาใช้ซ้ำได้ นั่นจะเพิ่มความสามารถในการอ่านและประสิทธิภาพ ฉันถามทีม BCL แล้วเราจะเห็น ...
Jon Skeet

3
มันเป็นวิธีการขยายแน่นอนว่ามันจะไม่สามารถอ่านได้สำหรับสมาชิกใหม่ของทีม ฉันคิดว่านั่นเป็นความคิดสำหรับสิ่งที่มีไหวพริบนี้ใช่ไหม สมาชิกใหม่จะรู้ได้ยังไงว่าเราฉลาดแค่ไหน?
MarkJ

17
ตกลง ... ฉันเพิ่งจะนำสิ่งนี้ไปปฏิบัติและไปกับด้วย - ดังนั้นคุณจะได้รับ "นี่คือ {0}" ด้วย ("ทดสอบ") และมันอ่านได้มากและสมเหตุสมผล FYI
klkitchens

89

สิ่งเหล่านี้มีประโยชน์หรือไม่?

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

mimicks pythons นี้ฟังก์ชั่น random.choice (seq) ดี
Daren Thomas

6
สิ่งที่สอง: ผมอยากแนะนำว่าOneOfควรจะยอมรับใด ๆ IList<T>จากนั้นคุณสามารถเสมอนอกจากนี้ยังมีที่ใช้เวลาเกินหนึ่งparamsหาเรื่องและเพียงแค่ผ่านไปนั้นลงในIList<T>การโอเวอร์โหลด ฉันให้คำตอบ (วิธีที่ด้านล่างขวาในขณะนี้) ด้วยNextBoolวิธีการที่คล้ายกับของคุณCoinTossแต่ด้วยการโอเวอร์โหลดที่ใช้probabilityพารามิเตอร์ ยิ่งไปกว่านั้น nit pick: โค้ดตัวอย่างของคุณจะส่งNullReferenceExceptionตั้งแต่randไม่มีการเตรียมใช้งาน
Dan Tao

3
+1 ฉันชอบสิ่งนี้มาก แต่ฉันชอบที่CoinTossจะนำไปใช้กับrng.NextDouble() < .5เพราะ.Next(int)ทำขึ้นภายใน.NextDouble()เพื่อให้คุณบันทึกนักแสดง * และเช็ค
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;
  }
}

ตัวอย่าง:

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

19
ฉันรักอันนี้ แต่ฉันพยายามที่จะตัดสินใจว่ามันถูกต้องที่จะทำให้การตรวจสอบขอบเขตรวมอยู่ในค่าขั้นต่ำ แต่ไม่รวมอยู่ในค่าสูงสุด ฉันสงสัยว่าจะทำให้เกิดความสับสน 5. ระหว่าง (5,10) เป็นจริง แต่ 5. ระหว่าง (1,5) เป็นเท็จ ไม่แน่ใจด้วยซ้ำว่าวิธีการที่เพื่อนช่วยจะช่วยได้ Thougts?
Steve Hiner

12
ชื่อ "IsBetween" จะไม่สมเหตุสมผลกว่านี้หรือ นอกจากนี้ยังอาจทำให้ IsBetweenInclusive และ IsBetweenExclusive ไม่มีความคิดที่จะใช้เป็นค่าเริ่มต้นแม้ว่า
fretje

2
@ Steve: มันสมเหตุสมผลกว่าถ้ามันเป็นส่วนขยายของวันที่และเวลา
Joel Coehoorn

16
สำหรับฉันระหว่างนัย: 5.Between (5,10) คืนเท็จและ 10.Between (5,10) คืนเท็จเช่นกัน นั่นทำให้ฉันรู้สึกเป็นธรรมชาติ
Alex Baranosky

3
สำหรับผมแล้วดูเหมือนว่าคนหลายคนมีความคิดที่แตกต่างกันไปตามธรรมชาติ ด้วยเหตุนี้จึงควรระบุสิ่งที่ใช้อย่างชัดเจน (เช่น Inclusive vs Exclusive) เนื่องจากนี่อาจเป็นแหล่งที่มาของข้อผิดพลาดที่ง่ายมาก
David Miani

58

วิธีการขยาย:

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

วิธีนี้ใช้ได้กับทุกประเภทและให้คุณเพิ่มช่วงของรายการในรายการเป็นพารามิเตอร์

ตัวอย่าง:

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

15
จะดีกว่าเช่นนี้ IList <T>

21
เพียงแค่ใช้ initializer การรวบรวม =>var list = new List<int>{5,4,8,4,2};
Arnis Lapsa

ทำไมไม่เพียงแค่เรียกรายการ <T> .AddRange (IEnumerable collection <T>) ภายในวิธีการของคุณ
Rauhotz

8
@Will: ที่จริงมันจะเป็นที่ดีที่สุดที่จะยอมรับICollection<T>; จากนั้นสามารถใช้กับตัวอย่างเช่นLinkedList<T>และHashSet<T>ไม่ใช่เพียงแค่การรวบรวมดัชนี
Dan Tao

2
แก้ไขเพื่อให้ความแปรปรวนร่วมใน pre-.net 4.0
BlueRaja - Danny Pflughoeft

55

โดยทั้งหมดใส่ไว้ในโครงการ codeplex

การทำให้เป็นอันดับ / วัตถุ Deserializing ไปยัง 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
ฉันถูกล่อลวงไปเรียกคนแรกToXml()(ชอบToString())
Jay Bazuzi

1
ขออภัยกับ OP หากเขาตั้งใจเขียนด้วยวิธีนี้ แต่การใช้ MemoryStreams AND XmlReader / XmlWriter นั้นมากเกินไป คลาส StringReader และ StringWriter นั้นสมบูรณ์แบบสำหรับการดำเนินการนี้
พอร์ตแมน

2
ระวังนี่ไม่ใช่ threadsafe คุณควรซิงโครไนซ์การเข้าถึงของคุณไปยังพจนานุกรม serialisers คงที่
Yann Schwartz

2
@Yann, @T มันง่ายกว่ามากถ้าคุณเพิ่งเพิ่มแอตทริบิวต์ "thread static" จากนั้นแคชใหม่จะถูกสร้างขึ้นต่อเธรด ไม่จำเป็นต้องทำการซิงโครไนซ์
Frank Krueger

1
@Jonathan C Dickinson: ปรากฏขึ้นจากเอกสาร MSDN ที่นี่msdn.microsoft.com/en-us/library/…ว่าตัวสร้างที่ใช้ (XmlSerializer ใหม่ (ชนิด)) ไม่มีปัญหาหน่วยความจำรั่ว ดังนั้นรหัสแคชอาจไม่จำเป็น?
slolife

46

ForEach สำหรับ 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);
    }
}

ตัวอย่างไร้เดียงสา:

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

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

ตัวอย่างที่ยอดเยี่ยม:

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

บันทึก:

นี้ไม่ได้เป็นเช่นSelectเพราะSelect คาดว่าฟังก์ชั่นของคุณจะส่งคืนบางสิ่งสำหรับการเปลี่ยนเป็นรายการอื่น

ForEach ช่วยให้คุณสามารถดำเนินการบางอย่างสำหรับแต่ละรายการโดยไม่มีการแปลง / การจัดการข้อมูล

ฉันทำสิ่งนี้เพื่อให้ฉันสามารถเขียนโปรแกรมในรูปแบบที่ใช้งานได้ดีขึ้นและฉันรู้สึกประหลาดใจที่ List มี ForEach ในขณะที่ IEnumerable ไม่ได้

วางสิ่งนี้ลงในโครงการ codeplex


13
โพสต์ว่าทำไมส่วนขยาย IEnumerable <T> ของ LINQ จึงไม่มี ForEach: stackoverflow.com/questions/317874/…
Neil

13
ฉันขอแนะนำให้อ่านวิธีนี้ก่อนใช้วิธี: blogs.msdn.com/ericlippert/archive/2009/05/18/…
jpbochi

2
@jpbochi: นี่เป็นเพียงแค่การ
ทำลายล้าง

1
@abatishchev และความคิดเห็นของคุณเป็นเพียงอคติต่อ Microsoft มันไม่ได้ทำให้โมฆะคำที่เขียนโดย Eric ข้อโต้แย้งของบางคนไม่ถูกต้องหรือไม่ถูกต้องเพียงเพราะ บริษัท ที่เขา / เธอทำงานให้
jpbochi

1
โดยวิธีการที่ฉันขอให้จุดหนึ่งที่ชัดเจน ฉันไม่ได้บอกว่าคุณไม่ควรใช้วิธีการขยาย ForEach นี้ ฉันเพิ่งบอกว่าคุณควรพิจารณาประเด็นที่ Eric เปิดเผยก่อนตัดสินใจใช้หรือไม่ ฉันอ่านมันและฉันตัดสินใจว่าจะไม่ใช้มัน คุณมีอิสระที่จะทำสิ่งที่คุณต้องการด้วยรหัสของคุณ
jpbochi

43

ส่วนขยายการแปลงของฉันที่ให้คุณทำ:

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

นี่มันคือโพสต์บน 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;
    }
}

คุณสามารถขอค่าเริ่มต้น (เรียกตัวสร้างที่ว่างเปล่าหรือ "0" สำหรับตัวเลข) เมื่อล้มเหลวระบุค่า "เริ่มต้น" (ฉันเรียกมันว่า "อื่น ๆ ") หรือขอ null (โดยที่ T: class) ฉันยังให้ทั้งสองรุ่นยกเว้นเงียบและรุ่น TryParse ทั่วไปที่ส่งกลับค่าบูลที่ระบุการกระทำที่ดำเนินการและพารามิเตอร์ออกเก็บค่าใหม่ ดังนั้นรหัสของเราสามารถทำสิ่งนี้

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

ฉันไม่สามารถทำให้ Nullable ประเภทนั้นกลิ้งลงไปได้อย่างหมดจด ฉันพยายามประมาณ 20 นาทีก่อนที่ฉันจะโยนผ้าเช็ดตัว


64
โดยส่วนตัวแล้วฉันไม่ใช่แฟนตัวยงของรหัสที่พยายาม / จับเพื่อตรวจสอบผลลัพธ์ ควรลองใช้ / จับสำหรับข้อผิดพลาดที่เกิดขึ้นนอกตรรกะที่กำหนดไว้ IMO hmmmmm
Pure.Krome

หากฉันไม่ต้องการให้คุณใช้รหัสฉันจะไม่โพสต์มัน! :)
TheSoftwareJedi

ในที่สุดสิ่งที่มองไม่เห็น ฉันชอบมัน. :)
Arnis Lapsa

8
อย่างน้อยคุณควรเปลี่ยนประโยค "catch" ให้จับเฉพาะข้อยกเว้นเหล่านั้นที่ ChangeType () จะเพิ่มขึ้นเมื่อไม่สามารถ "แปลง" ข้อมูลอ้างอิงได้ ฉันคิดว่าคุณไม่ต้องการที่จะมี OutOfMemoryException, ExecutionEngineException, ThreadAbortException ใด ๆ หรือเหมือนกันว่าเป็นข้อผิดพลาดในการแปลง สิ่งเหล่านั้นจะเป็นการยากที่จะติดตามข้อผิดพลาด
Christian.K

2
ฉันเชื่อว่าToOrNullมีพฤติกรรมเช่นเดียวกับที่แน่นอนToOrDefault(เช่นหากคุณโทรหาToOrDefaultประเภทอ้างอิงที่มีการแปลงไม่สำเร็จก็จะกลับมาnull) แต่ที่สำคัญกว่านั้นคือฉันรู้สึกซ้ำซ้อนเพราะvar s = myObject as stringทำสิ่งเดียวกันให้สำเร็จvar s = myObject.ToOrNull<string>()- แต่โดยไม่ต้องจับInvalidCastExceptionต้อง ฉันพลาดอะไรไปรึเปล่า?
ด่านเต่า

43

ฉันมีวิธีการเสริมสำหรับการบันทึกข้อยกเว้น:

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

และมันถูกใช้แบบนี้:

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

[ขอโทษที่โพสต์สองครั้ง; คนที่สองได้รับการออกแบบที่ดีกว่า :-)]


2
ควรอ่านบันทึกโมฆะคงที่สาธารณะ (ข้อยกเว้น obj นี้) {} อาจจะ?
Chris S

ฉันคิดว่านี่เป็นสิ่งที่ดีสำหรับ BCL หรือข้อยกเว้นของบุคคลที่สาม แต่ถ้าคุณหมุนประเภทข้อยกเว้นของคุณเองคุณสามารถทำการบันทึกในคลาสข้อยกเว้นพื้นฐานของคุณ ด้วยวิธีนี้คุณไม่จำเป็นต้องเรียก 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);
    }
}

มีประโยชน์ในการแยกสตริงเป็น Enum

public enum TestEnum
{
    Bar,
    Test
}

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

เครดิตไปที่ Scott Dorman

--- แก้ไขสำหรับโครงการ Codeplex ---

ฉันถามสกอตต์ดอร์แมนว่าเขาจะรังเกียจเราหรือไม่ที่จะเผยแพร่โค้ดของเขาในโครงการ Codeplex นี่คือคำตอบที่ฉันได้รับจากเขา:

ขอบคุณสำหรับการเฮดอัพทั้งในโพสต์ SO และโครงการ CodePlex ฉันตอบคำถามของคุณแล้ว ใช่รหัสนี้มีผลบังคับใช้ในโดเมนสาธารณะในปัจจุบันภายใต้สิทธิ์การใช้งาน CodeProject Open ( http://www.codeproject.com/info/cpol10.aspx )

ฉันไม่มีปัญหากับการรวมอยู่ในโครงการ CodePlex และหากคุณต้องการเพิ่มฉันในโครงการ (ชื่อผู้ใช้คือ sdorman) ฉันจะเพิ่มวิธีการนั้นพร้อมด้วยวิธีการ Enum helper เพิ่มเติม


สถานการณ์การแจงส่วนนี้เกิดขึ้นตลอดเวลา ... ต้องใส่สิ่งนี้ใน lib :-) ของฉัน
chakrit

ว้าวฉันได้เขียนวิธีการจับคู่สตริงกับ enums (เพิ่งเริ่มใช้. NET) ขอบคุณสิ่งนี้จะช่วยได้อย่างแน่นอน!
เควิน

4
คุณอาจพิจารณาตั้งชื่อ ToEnum นี้ <> () เนื่องจากมันมาหลังจากวัตถุ
Neil

โปรดทราบว่า Enum.TryParse <T> ได้รับการเพิ่มใน Net 4.0 - blogs.msdn.com/bclteam
Dan Diplo

1
ฉันไม่คิดว่าวิธีนี้ควรใช้ Trim การตัดอินพุตควรเป็นความรับผิดชอบของผู้โทร
CodesInChaos

32

ฉันพบว่าอันนี้มีประโยชน์มาก:

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

คุณสามารถใช้มันใน CodePlex


2
ใครบางคนใจดีพอที่จะอธิบายให้คนที่มีพรสวรรค์น้อยของเราได้หรือไม่
jpbochi

ฮ่าฮ่าฮ่าแค่อ่านบทความ (ความคิดเห็นของโจเอลด้านบน) - ตลกจริง ๆ แต่เมื่ออยู่ในเรือลำเดียวกัน (ในตอนท้ายของการรับไม่ใช่พอลล่าตอนท้าย) มันดูตลกเท่านั้น! ครั้งหนึ่งเคยมีผู้รับเหมาเข้ามาทำงานในโครงการฉันเป็นผู้ออกแบบ / ผู้นำการพัฒนา - เธอไม่ได้อยู่ภายใต้การควบคุมโดยตรงของฉัน แต่ได้รับมอบหมายงานจากรายชื่อทีมงานของฉัน ผู้บังคับบัญชายกย่องเธอว่ายอดเยี่ยม (แม้กระทั่งการว่าจ้างเธออีกครั้งในภายหลังในฐานะผู้นำนักพัฒนา! ไม่เคยรุ่งเช้าเลยว่าโค้ดทุกชิ้นที่เธอเขียนหรือออกแบบไม่ได้ผลิตออกมาและทุกอย่างจะต้องถูกเขียนใหม่ทั้งหมดตั้งแต่ต้นโดยทีมของฉัน!
Wolf5370

31

DateTimeExtensions

ตัวอย่าง:

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
ฉันขอแนะนำให้เปลี่ยนชื่อ "SetTime" เป็น "WithTime" เนื่องจากไม่ได้ตั้งค่าไว้ในค่าเดิม ดี แต่อย่างอื่น
Jon Skeet

28
DateTime.Now.First () - ก่อนอื่นคืออะไร มันชัดเจนจากโค้ดตัวอย่างเท่านั้น
mackenir

2
ดีมาก. แต่ยอมรับว่าชื่ออาจจะดีกว่ามาก
bovium

DateTime.Now.First จะชัดเจนเพียงพอใน Intellisense หากวิธีการได้รับการบันทึกไว้เป็นอย่างดี
Ryan Lundy

29

gitorious.org/cadenzaเป็นห้องสมุดเต็มรูปแบบของวิธีการขยายที่มีประโยชน์ที่สุดที่ฉันเคยเห็น


12 วิธีการขยายพื้นฐานที่เป็นธรรม ฉันรู้สึกท้อแท้เล็กน้อยจากหินขาวดำ
mackenir

(ผมพูดถึงรุ่นที่วางจำหน่ายไม่หนึ่งที่คุณจำเป็นต้องใช้แหล่งการควบคุมที่จะได้รับ)
mackenir

28

นี่คือสิ่งที่ฉันใช้บ่อยสำหรับการจัดรูปแบบงานนำเสนอ

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

อ๊ะการจัดการข้อยกเว้นของโปเกมอนจะซ่อนปัญหาเช่น ThreadAbortException และอื่น ๆ โปรดติดตามบางสิ่งที่เฉพาะเจาะจง
JBRWilkinson

28

นี่คือสิ่งที่ต้องทำสำหรับตัวเลขโรมัน ไม่ได้ใช้บ่อย แต่อาจมีประโยชน์ การใช้งาน:

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

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

แหล่งที่มา:

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

นั่นทำให้ผมนึกถึงหลาม PEP 313 ซึ่งเป็นเรื่องตลก Fools เมษายนที่จะรวมตัวอักษรตัวเลขโรมันในหลาม: python.org/dev/peps/pep-0313
torial

25

วิธีที่สะดวกในการจัดการกับขนาด:

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

ในความคิดของฉันนี่เป็นสไตล์การเขียนโค้ดที่แย่จริงๆ ค่าคงที่ควรใช้แทนไม่ใช่ตรรกะที่สับสน
xxbbcc

24

สำหรับการควบคุม 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));
}

IsDesignTime การใช้งาน:

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

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

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

การใช้งาน SetDropdownWidth:

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

ฉันลืมที่จะพูดถึงอย่าลังเลที่จะใช้สิ่งเหล่านี้ใน Codeplex ...


1
ดังที่กล่าวมานี้มีไว้สำหรับ WinForms เท่านั้น มันอาจทำงานกับ WPF แต่มีปัญหา (อธิบายไว้ในความคิดเห็นเกี่ยวกับ WPF ที่msdn.microsoft.com/en-us/library/ ...... ) ทางออกที่ดีที่สุดสำหรับ WPF ที่ฉันพบได้อธิบายไว้ในgeekswithblogs.net/lbugnion/archive/2009/09/05/ … (แม้ว่าเนื่องจากเป็นคุณสมบัติคงที่มันไม่ได้ทำงานเป็นวิธีการขยาย)
scobi

23

ThrowIfArgumentIsNull เป็นวิธีที่ดีในการทำ null ตรวจสอบว่าเราทุกคนควรทำ

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

ด้านล่างเป็นวิธีการใช้งานและใช้ได้กับคลาสทั้งหมดในเนมสเปซของคุณหรือทุกที่ที่คุณใช้เนมสเปซภายใน

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

สามารถใช้รหัสนี้กับโครงการCodePlexได้


ฉันชอบสิ่งนี้เช่นกันจอนมีไว้ในตัวเขาและฉันใช้บางอย่างที่คล้ายกันจากอัมโบร
cfeduke

ใช่ นี่เป็นวิธีการขยาย kewl ด้วยเช่นกัน :)
Pure.Krome

3
ถ้าคุณใช้ ArgumentNullException-constructor ที่มีเพียง 1 สายอักขระอาร์กิวเมนต์นั้นจะต้องเป็นเพียงชื่อพารามิเตอร์และไม่ใช่ข้อความแสดงข้อผิดพลาด ดังนั้นโค้ดของคุณควรมีลักษณะดังนี้: if (obj == null) ให้ส่ง ArgumentNullException ใหม่ (parameterName);
Tommy Carlier

ฉันจะใช้default(T)สิ่งนี้และลบข้อกำหนดของชั้นเรียน
Joel Coehoorn

1
@Joel: ค่าที่ไม่ใช่ค่าเริ่มต้นสำหรับประเภทเนทีฟเป็นอาร์กิวเมนต์ที่ถูกกฎหมายมากกว่าค่า Null การตรวจสอบกับโมฆะทำให้ฉันสมเหตุสมผลกว่าการตรวจสอบกับค่าเริ่มต้น แน่นอนฉันเพียงแค่พูดคุยความคิดทั้งหมดโดยการพูดหรือRequire.ThatArgument(input != null) Require.ThatArgument(personId > 0)มันไม่ได้ใช้โค้ดมากกว่านั้นมีความยืดหยุ่นมากกว่าและอ่านได้อย่างดี ฉันมีการแทนที่เพิ่มเติมที่ใช้ funcs เมื่อคุณต้องการกำหนดข้อความแสดงข้อผิดพลาดหรือข้อยกเว้นเอง
StriplingWarrior

22

ฉันคิดถึง คำสั่งด้วย Visual Basicเมื่อย้ายไปที่ C # ดังนั้นที่นี่จะไป:

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

และนี่คือวิธีการใช้ใน C #:

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

ประหยัดการพิมพ์จำนวนมาก!

เปรียบเทียบสิ่งนี้กับ:

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

ใส่ในโครงการ codeplex


4
แค่เดา ​​แต่คิดว่าจะเกิดอะไรขึ้นถ้า T ของคุณเป็น struct
Rauhotz

5
ฉันยังใช้ไวยากรณ์ initializer คุณสมบัติ c # 3.0 ทุกที่ที่เป็นไปได้เพื่อให้ได้ผลลัพธ์เดียวกัน
Steve

3
@ Chakrit นี่เป็นตัวอย่าง มันจะใช้เฉพาะเมื่อสร้างวัตถุปุ่ม n = ปุ่มใหม่ {ชื่อ = "Button1", ความกว้าง = 100, ความสูง = 20, เปิดใช้งาน = จริง};
Steve

1
สิ่งนี้จะเป็นประโยชน์สำหรับเมื่อคุณมีเหตุการณ์มากมายที่จะต้องเชื่อมต่อเพราะไวยากรณ์ตัวเริ่มต้นของคุณสมบัติ C # ไม่รองรับเหตุการณ์
Gabe

1
สิ่งนี้ยังเป็นประโยชน์นอกการเริ่มต้นคุณสมบัติเนื่องจากคุณสามารถใช้ได้เมื่อสร้างวัตถุใหม่เท่านั้น ส่วนขยายนี้สามารถทำงานกับวัตถุที่สร้างไว้ก่อนหน้านี้
Brady Moritz

18

ใช้ camelCaseWord หรือ PascalCaseWord และ "wordifies" มันคือ 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])" ) );
}

ฉันมักจะใช้ร่วมกับทุน

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

ตัวอย่างการใช้งาน

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

ฟรีที่จะใช้ในโครงการ codeplex


การรวมในตัวพิมพ์ใหญ่นั้นค่อนข้างแย่สำหรับประสิทธิภาพเนื่องจากมันสร้างอินสแตนซ์ของสตริงจำนวนมาก ทำไมไม่ใช้ word.Substring (1) แทน?
โทมัส Levesque

17

ฉันพบสิ่งนี้มีประโยชน์

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

มันจะลบการตรวจสอบเป็นโมฆะในรหัสโทร ตอนนี้คุณสามารถทำได้

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

ใช่ถ้ามีคนลืม "รูปแบบวัตถุ Null" วิธีนี้มีประโยชน์ในการแก้ไข การรวบรวมไม่ควรเป็นโมฆะ
Pavel Hodek

16

แปลง double เป็น string ที่จัดรูปแบบโดยใช้วัฒนธรรมที่ระบุ:

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

ตัวอย่าง:

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

13
คุณควรใช้ทศนิยมสำหรับสกุลเงินอื่น ๆ ที่คุณจะได้รับการปัดเศษปัญหา
แอนดรูวัว

สิ่งที่เกี่ยวกับการใช้ Enum ที่ในพารามิเตอร์แทนของสตริงธรรมดา
Rulas

15

ด้านล่างเป็นวิธีส่วนขยายที่ปรับใช้รหัสของ Rick Strahl (และความคิดเห็นด้วย) เพื่อหยุดคุณไม่ต้องเดาหรืออ่านเครื่องหมายลำดับไบต์ของอาร์เรย์ไบต์หรือไฟล์ข้อความทุกครั้งที่คุณแปลงเป็นสตริง

ตัวอย่างช่วยให้คุณทำ:

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

หากคุณพบข้อบกพร่องใด ๆ โปรดเพิ่มความคิดเห็น อย่าลังเลที่จะรวมไว้ในโครงการ 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();
            }
        }
    }
}

วิธีที่มีประโยชน์มาก แต่ฉันไม่คิดว่ามันควรจะเป็นและวิธีการขยาย
Pop Catalin

หากคุณกำลังเขียนโปรแกรมแก้ไขข้อความก็อาจใบสำคัญแสดงสิทธิวิธีขยาย แต่ผมเห็นด้วยมากที่สุดของเวลามันอาจจะไม่มากไปกว่าวิธีการส่วนตัวคงที่
คริส S

15

นี่คือสิ่งที่ฉันเพิ่งสร้างขึ้นวันนี้

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

มันช่วยให้คุณทำสิ่งนี้:

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

อันไหนที่คล่องแคล่วกว่าและ (IMO) อ่านง่ายกว่านี้:

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

1
หากฉันต้องการthingy.NullOr(t => t.Count)ที่Countเป็น int? คุณควรกลับdefault(TReturn)มากกว่า null ซึ่งคุณไม่จำเป็นต้องมีclassข้อ จำกัด และมันจะใช้ได้กับประเภทของค่าด้วยเช่นกัน
Thomas Levesque

2
TIN ควรจะต้องเป็นคลาสมิฉะนั้นวิธีการขยายทั้งหมดนี้ไม่มีเหตุผล (ประเภทค่าไม่สามารถเป็นโมฆะ) และตัวอย่างของคุณกับ t.Count นั้นใช้ได้กับวิธีการต่อไปนี้ คุณลองมองดูครั้งที่สองดูไหม?
scobi

@Scott: นี่เป็นวิธีที่มีประโยชน์สำหรับปัญหาทั่วไป อย่างไรก็ตามฉันเชื่อว่าTReturn elseValue = default(TReturn)มีเพียง. NET 4.0 เท่านั้น ฉันมี 3.5 SP1 และฉันไม่เคยเห็นโครงสร้างนั้น (ไม่มีคอมไพเลอร์ของฉัน) ฉันแค่ย้ายสิ่งนี้ไปที่ข้างในวิธี อย่างไรก็ตามประเด็นหนึ่งคือการชกมวยประเภท nullable ไปยังวัตถุสำหรับใช้กับวิธีการให้ผลลัพธ์ที่ไม่คาดคิด (0 vs null คาด)
Jim Schubert

@ จิม: default(T)คำหลักอยู่ที่นั่นมาตั้งแต่ VS2005 แต่ฉันคิดว่าพารามิเตอร์เริ่มต้นคือคุณลักษณะ. NET 4 ใหม่ วิธีที่ง่ายรอบตัวมันควรจะมีสองรูปแบบหนึ่งที่ใช้พารามิเตอร์และหนึ่งที่ไม่ ฉันจะอัปเดตคำตอบเพื่อให้เข้ากันได้กับ CLR 2.0 เกี่ยวกับมวย - defaultที่จุดของ มันจะเป็นข้อมูลที่เริ่มต้นได้ 0 สำหรับประเภทค่าและเป็นโมฆะสำหรับทุกประเภทการอ้างอิง TReturn ของประเภทค่าควรยังคงไม่ได้ทำกล่องตลอดทางผ่านฟังก์ชั่น
scobi

@Scott: คำถามของฉันเกี่ยวกับพารามิเตอร์เริ่มต้นซึ่งฉันเห็นเฉพาะในภาษาไดนามิกเช่น Ruby จุดของฉันเกี่ยวกับประเภท nullable คือการกลับมาx.Valueควรกลับ null (ถ้าเช่นint?เป็นโมฆะ) หรือค่าถ้าint?มีค่า การส่งคืน0เมื่อint? x = nullถูกส่งผ่านและบรรจุกล่องไปยังวัตถุเป็นกรณีแปลก ๆ ฉันเคยเห็นการตรวจสอบที่คล้ายกันสำหรับประเภท nullable ในไลบรารีเช่น fluent nhibernate และ linfu (ฉันคิดว่า) สำหรับกรณีเฉพาะนี้ช่วยให้คุณสามารถวางข้อ จำกัด ของคลาสตามที่แนะนำไว้ก่อนหน้านี้
Jim Schubert

14

"โปรดทำเครื่องหมายคำตอบของคุณด้วยการยอมรับเพื่อใส่รหัสในโครงการ Codeplex"

ทำไม? เนื้อหาทั้งหมดในเว็บไซต์นี้ภายใต้CC-by-sa-2.5ดังนั้นเพียงแค่ใส่ส่วนต่อขยายของคุณภายใต้ใบอนุญาตเดียวกันและคุณสามารถใช้มันได้อย่างอิสระ

อย่างไรก็ตามนี่คือฟังก์ชั่น String.Reverse ตามคำถามนี้

/// <summary>
/// Reverse a String
/// </summary>
/// <param name="input">The string to Reverse</param>
/// <returns>The reversed String</returns>
public static string Reverse(this string input)
{
    char[] array = input.ToCharArray();
    Array.Reverse(array);
    return new string(array);
}

String ไม่ได้ติดตั้ง IEnumerable <char> แล้วใช่ไหม ดังนั้นคุณเพียงแค่ต้องส่งคืนสตริงใหม่ (input.Reverse ());
Iain Galloway

การใช้งานโดยใช้ StringBuilder ควรเร็วขึ้น
CodesInChaos

1
@CodeInChaos การเปรียบเทียบในstackoverflow.com/questions/228038วัดว่า StringBuilder ช้ากว่า
Michael Stum

คุณถูก. ดูเหมือนว่าข้อกำหนดด้านความปลอดภัยของเธรด (อาจเป็นไปได้ที่จะทำให้มั่นใจว่าสตริงที่ส่งคืนโดย ToString ไม่สามารถเปลี่ยนแปลงได้) ทำให้ StringBuilder ช้าลงมาก
CodesInChaos

2
หวังว่าคุณจะไม่ได้รับตัวแทนหรือการรวมตัวละคร
dalle

14

ฉันเบื่อการตรวจสอบ null ที่น่าเบื่อในขณะที่ดึงค่าจาก MySqlDataReader ดังนั้น:

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

แน่นอนว่าสิ่งนี้สามารถใช้ได้กับ SqlDataReader ใด ๆ


ทั้ง hangy และ Joe มีความเห็นที่ดีเกี่ยวกับวิธีการทำเช่นนี้และฉันมีโอกาสที่จะใช้บางสิ่งที่คล้ายกันในบริบทที่แตกต่างกันดังนั้นนี่คือรุ่นอื่น:

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
ซึ่งควรทำงานเป็นวิธีเสริมสำหรับ IDataReader
hangy

2
จริง ๆ แล้วทำให้พารามิเตอร์ "this" ของชนิด IDataRecord เพื่อความเข้ากันได้สูงสุด ในรุ่นนี้ของฉันฉันมีเกินพิกัดที่ใช้ลำดับซึ่งเรียก fieldName รุ่น บันทึก "GetOrdinal" ตามด้วยการค้นหาตามชื่อ
Joel Mueller

มีการใช้งานที่เหมาะสมซึ่งสามารถจัดการกับค่าประเภทใดก็ได้: rabdullin.com/journal/2008/12/6/…
Rinat Abdullin

ขอบคุณ Rinat ฉันใช้วิธีการแบบทั่วไปเดียว - ดูstackoverflow.com/questions/303287
Adam Lassek

วิธีการทั้งหมดเหล่านี้ดูเหมือนจะไม่จำเป็นเนื่องจากคุณสามารถใช้asคำหลักเพื่อรับค่าจากตัวอ่านที่อนุญาตให้มีค่าว่าง หากคุณรวมตัว??ดำเนินการรวมศูนย์ว่างกับตัวดำเนินการเป็นคุณยังสามารถมีค่าเริ่มต้นที่ไม่เป็นศูนย์สำหรับการไปที่ประเภทค่าโดยตรง ดูstackoverflow.com/questions/746767/…
stevehipwell

14

มันทำให้ฉันหงุดหงิดที่ LINQ ให้ OrderBy แก่ฉันซึ่งใช้คลาส IComparer เป็นอาร์กิวเมนต์ แต่ไม่สนับสนุนการส่งผ่านในฟังก์ชันตัวเปรียบเทียบแบบไม่ระบุตัวตนแบบง่าย ฉันแก้ไขมัน

คลาสนี้สร้าง IComparer จากฟังก์ชันตัวเปรียบเทียบของคุณ ...

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

... และวิธีการขยายเหล่านี้เปิดเผยการสั่งซื้อเกินพิกัดใหม่ของฉันในการนับจำนวน ฉันสงสัยว่ามันใช้งานได้กับ LINQ ไปยัง SQL แต่มันยอดเยี่ยมสำหรับ LINQ กับวัตถุ

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

คุณสามารถวางมันลงบน codeplex ได้ถ้าต้องการ


13

อันนี้สำหรับ MVC จะเพิ่มความสามารถในการสร้าง<label />แท็กให้กับHtmlตัวแปรที่มีอยู่ในทุกViewPageๆ หวังว่ามันจะเป็นประโยชน์กับผู้อื่นที่พยายามพัฒนาส่วนขยายที่คล้ายกัน

ใช้:

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

เอาท์พุท:

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

รหัส:

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

ตรวจสอบ MvcContrib.FluentHtml
อานิส Lapsa

สิ่งนี้อาจจะซ้ำกับตัวอักษรแทน
Mark Hurd

12

เปลี่ยนสิ่งนี้:

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

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

command.Parameters.Add(param);

... ลงในนี้:

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

... โดยใช้วิธีการขยายนี้:

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

วิธีการขยาย ADO.NET เพิ่มเติม: DbExtensions

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.