关于.NET:您最喜欢的扩展方法是什么?(codeplex.com/extensionoverflow)

What are your favorite extension methods for C#? (codeplex.com/extensionoverflow)

让我们列出一个答案列表,您可以在其中发布您最喜欢的扩展方法。

要求是必须发布完整的代码,以及如何使用它的示例和解释。

基于对这个主题的高度关注,我在codeplex上建立了一个名为extensionoverflow的开源项目。

请在您的答案上注明接受将代码放入codeplex项目。

请发布完整的源代码,而不是链接。

CODULTEX新闻:

2010年8月24日codeplex页面现在位于:http://extensionoverflow.codeplex.com/

11.11.2008现在实现了xmlserialize/xmlserialize,并对单元进行了测试。

11.11.2008仍有空间容纳更多的开发者。-现在加入!

2008年11月11日第三位出资人加入ExtensionOnVerFlow,欢迎来到BKristensen

11.11.2008 FormatWith现已实施并进行单元测试。

2008年11月9日,第二位出资人加入了ExtensionOverflow。欢迎来到查克里特。

09.11.2008我们需要更多的开发者。;-)

2008年11月9日Throwifargumentinsull现已实施,并在codeplex上进行了单元测试。


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

允许我替换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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....
}

用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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....
}


我在MiscUtil项目中有各种扩展方法(这里提供了完整的源代码——我不会在这里重复它)。我最喜欢的,其中一些涉及其他类(如范围):

日期和时间资料-主要用于单元测试。不确定我会在生产中使用它们:)

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

距离和步法-这要归功于马克·格雷维尔的操作人员才能做到:

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

比较:

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

参数检查:

1
x.ThrowIfNull("x");

应用于匿名类型(或具有适当属性的其他类型)的Linq to XML:

1
2
3
4
// <Name>Jon</Name><Age>32</Age>
new { Name="Jon", Age=32}.ToXElements();
// Name="Jon" Age="32" (as XAttributes, obviously)
new { Name="Jon", Age=32}.ToXAttributes()

push-linq-在这里解释会花很长时间,但要搜索它。


字符串。格式快捷方式:

1
2
3
4
5
6
7
8
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);
    }
}

例子:

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

要快速复制和粘贴,请转到此处。

你不觉得键入"some string".F("param")而不是string.Format("some string","param")更自然吗?

要获得更易读的名称,请尝试以下建议之一:

1
2
3
4
5
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");


这些有用吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
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!");


1
2
3
4
5
6
7
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;
  }
}

例子:

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


扩展方法:

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

该方法适用于所有类型,并允许您将一系列项目作为参数添加到列表中。

例子:

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


无论如何,把它放到codeplex项目中。

将对象序列化/反序列化为XML:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/// <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.
    }
}


用于IEnumerables的foreach

1
2
3
4
5
6
7
8
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);
    }
}

幼稚的例子:

1
2
3
4
var buttons = GetListOfButtons() as IEnumerable<Button>;

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

酷的例子:

1
2
3
4
5
6
7
8
// 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希望您的函数返回一些东西,以便转换为另一个列表。

for each只允许您为每个项执行一些操作,而不需要任何转换/数据操作。

我这样做是为了能够以更实用的方式编程,我很惊讶列表中有foreach,而IEnumerable没有。

把这个放到codeplex项目中


我的转换扩展允许您执行以下操作:

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

就在这里,就像在softwarejedi.com上发布的那样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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"),指定"默认"值(我称之为"其他"),或者请求空值(其中t:class)。我还提供了无声异常模型和一个典型的Tryparse模型,它返回一个指示所采取操作的bool,out参数保存新值。所以我们的代码可以这样做

1
2
3
4
5
6
7
8
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>();

我不能让可以为空的类型非常干净地进入整个过程。我试了20分钟才把毛巾扔了进去。


我有一个记录异常的扩展方法:

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

它的用法如下:

1
2
3
4
5
6
7
8
try
{
    //Your stuff here
}
catch(Exception ex)
{
    ex.Log();
}

[抱歉发了两次,第二次设计得更好:-)]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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);
    }
}

用于将字符串解析为枚举。

1
2
3
4
5
6
7
8
9
10
11
12
13
public enum TestEnum
{
    Bar,
    Test
}

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

学分归斯科特·多曼

---编辑codeplex项目---

我问过ScottDorman,他是否介意我们在CodePlex项目中发布他的代码。这是我从他那里得到的答复:

Thanks for the heads-up on both the SO post and the CodePlex project. I have upvoted your answer on the question. Yes, the code is effectively in the public domain currently under the CodeProject Open License (http://www.codeproject.com/info/cpol10.aspx).

I have no problems with this being included in the CodePlex project, and if you want to add me to the project (username is sdorman) I will add that method plus some additional enum helper methods.


我觉得这个很有用:

1
2
3
4
5
6
7
public static class PaulaBean
{
    private static String paula ="Brillant";
    public static String GetPaula<T>(this T obj) {
        return paula;
    }
}

您可以在codeplex上使用它。


日期时间扩展

实例:

1
2
3
4
5
6
7
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();


gitorious.org/cadenza是我见过的一些最有用的扩展方法的完整库。


这里有一个我经常使用的演示格式。

1
2
3
4
5
6
7
8
9
10
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());
}


这是罗马数字的"到"和"从"。不常用,但可以方便使用。用途:

1
2
3
4
5
6
7
if ("IV".IsValidRomanNumeral())
{
   // Do useful stuff with the number 4.
}

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

来源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
    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();
        }
    }


处理尺寸的便捷方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
        };
    }
}


对于WinForm控件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/// <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用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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用法:

1
2
3
4
5
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上随意使用这些…


Throwifargumentinsull是一种很好的方法来执行我们都应该做的空检查。

1
2
3
4
5
6
7
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");
    }
}

下面是使用它的方法,它适用于您的命名空间中的所有类或您在其中使用命名空间的任何地方。

1
2
3
4
5
6
7
internal class Test
{
    public Test(string input1)
    {
        input1.ThrowIfArgumentIsNull("input1");
    }
}

可以在codeplex项目中使用此代码。


当移动到c时,我错过了Visual Basic的with语句,所以这里是:

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

下面是如何在C中使用它:

1
2
3
4
5
someVeryVeryLonggggVariableName.With(x => {
    x.Int = 123;
    x.Str ="Hello";
    x.Str2 =" World!";
});

节省了大量的打字时间!

将此项与:

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

放入codeplex项目


取一个camel case word或pascalecaseword并"用词化"它,即camel case word=>camel case word

1
2
3
4
5
6
7
8
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])" ) );
}

我经常把它与大写字母连用

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

示例用法

1
2
3
4
5
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项目中免费使用


我觉得这个有用

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

它删除调用代码中的空签入。你现在可以了

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


将使用指定区域性格式化的双精度转换为字符串:

1
2
3
4
5
6
7
8
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));
  }
}

例子:

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


下面是一个扩展方法,它调整了Rick Strahl的代码(以及注释),使您不必在每次将字节数组或文本文件转换为字符串时猜测或读取其字节顺序标记。

代码片段允许您简单地执行以下操作:

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

如果发现任何错误,请添加到评论中。请随意将其包含在CodePlex项目中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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();
            }
        }
    }
}


这是我今天刚创建的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 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); }

它允许您这样做:

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

比这更流利,也更容易阅读:

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


我厌倦了从mysqldatareader中提取值时冗长的空检查,因此:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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都对如何做到这一点发表了一些很好的评论,此后我有机会在不同的上下文中实现类似的东西,所以这里是另一个版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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);
}


"请将您的答案标记为接受将代码放入codeplex项目。"

为什么?这个站点上所有的东西都在cc-by-sa-2.5下,所以只要将扩展溢出项目放在同一个许可证下,就可以自由使用它。

无论如何,这里有一个字符串。根据这个问题,反转函数。

1
2
3
4
5
6
7
8
9
10
11
/// <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);
}


Linq给了我一个orderby,它将实现IComparer的类作为参数,但不支持传入一个简单的匿名比较器函数,这让我很恼火。我纠正了这一点。

此类从比较器函数创建一个IComparer…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/// <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
}

…这些扩展方法在可枚举项上公开了我的新orderby重载。我怀疑这对linq-to-sql有效,但对于linq-to对象来说很好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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上。


这一个是针对MVC的,它将生成标记的能力添加到每个ViewPage中可用的Html变量中。希望它对其他试图开发类似扩展的人有用。

用途:

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

输出:

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

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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);
    }
}


把这个变成:

1
2
3
4
5
6
7
8
DbCommand command = connection.CreateCommand();
command.CommandText ="SELECT @param";

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

command.Parameters.Add(param);

…进入这个:

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

…使用此扩展方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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


我最喜欢的是字符串上的islike()扩展名。islike()与vb的like运算符匹配,当您不想在regex上编写完整的表达式来解决您的问题时,它非常方便。用法如下:

1
2
3
4
5
6
7
8
"abc".IsLike("a*"); // true
"Abc".IsLike("[A-Z][a-z][a-z]"); // true
"abc123".IsLike("*###"); // true
"hat".IsLike("?at"); // true
"joe".IsLike("[!aeiou]*"); // true

"joe".IsLike("?at"); // false
"joe".IsLike("[A-Z][a-z][a-z]"); // false

下面是代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public static class StringEntentions {
    /// <summary>
    /// Indicates whether the current string matches the supplied wildcard pattern.  Behaves the same
    /// as VB's"Like" Operator.
    /// </summary>
    /// <param name="s">The string instance where the extension method is called</param>
    /// <param name="wildcardPattern">The wildcard pattern to match.  Syntax matches VB's Like operator.</param>
    /// <returns>true if the string matches the supplied pattern, false otherwise.</returns>
    /// <remarks>See http://msdn.microsoft.com/en-us/library/swf8kaxw(v=VS.100).aspx</remarks>
    public static bool IsLike(this string s, string wildcardPattern) {
        if (s == null || String.IsNullOrEmpty(wildcardPattern)) return false;
        // turn into regex pattern, and match the whole string with ^$
        var regexPattern ="^" + Regex.Escape(wildcardPattern) +"$";

        // add support for ?, #, *, [], and [!]
        regexPattern = regexPattern.Replace(@"\[!","[^")
                                   .Replace(@"\[","[")
                                   .Replace(@"\]","]")
                                   .Replace(@"\?",".")
                                   .Replace(@"\*",".*")
                                   .Replace(@"\#", @"\d");

        var result = false;
        try {
            result = Regex.IsMatch(s, regexPattern);
        }
        catch (ArgumentException ex) {
            throw new ArgumentException(String.Format("Invalid pattern: {0}", wildcardPattern), ex);
        }
        return result;
    }
}


与上面的字符串as和is相似,但对所有对象都是全局的。

这很简单,但我经常用拳击来缓解帕伦斯的爆发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static class ExtensionMethods_Object
{
    [DebuggerStepThrough()]
    public static bool Is<T>(this object item) where T : class
    {
        return item is T;
    }

    [DebuggerStepThrough()]
    public static bool IsNot<T>(this object item) where T : class
    {
        return !(item.Is<T>());
    }

    [DebuggerStepThrough()]
    public static T As<T>(this object item) where T : class
    {
        return item as T;
    }
}

我很高兴这段代码可以在codeplex中使用,事实上它已经被使用了。


请在此处查找更多示例:www.extensionmethod.net


您可以从Random类获得很多功能。

下面是我经常使用的一些扩展方法。有了这些,除了NextNextDouble外,Random类还提供了NextBoolNextCharNextDateTimeNextTimeSpanNextDouble(接受minValuemaxValue参数,我个人最喜欢的参数是NextString。有更多(NextByteNextShortNextLong等);但这些都是为了完整性,没有得到足够的使用。所以我没有在这里包含它们(这个代码足够长!).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// todo: implement additional CharType values (e.g., AsciiAny)
public enum CharType {
    AlphabeticLower,
    AlphabeticUpper,
    AlphabeticAny,
    AlphanumericLower,
    AlphanumericUpper,
    AlphanumericAny,
    Numeric
}

public static class RandomExtensions {
    // 10 digits vs. 52 alphabetic characters (upper & lower);
    // probability of being numeric: 10 / 62 = 0.1612903225806452
    private const double AlphanumericProbabilityNumericAny = 10.0 / 62.0;

    // 10 digits vs. 26 alphabetic characters (upper OR lower);
    // probability of being numeric: 10 / 36 = 0.2777777777777778
    private const double AlphanumericProbabilityNumericCased = 10.0 / 36.0;

    public static bool NextBool(this Random random, double probability) {
        return random.NextDouble() <= probability;
    }

    public static bool NextBool(this Random random) {
        return random.NextDouble() <= 0.5;
    }

    public static char NextChar(this Random random, CharType mode) {
        switch (mode) {
            case CharType.AlphabeticAny:
                return random.NextAlphabeticChar();
            case CharType.AlphabeticLower:
                return random.NextAlphabeticChar(false);
            case CharType.AlphabeticUpper:
                return random.NextAlphabeticChar(true);
            case CharType.AlphanumericAny:
                return random.NextAlphanumericChar();
            case CharType.AlphanumericLower:
                return random.NextAlphanumericChar(false);
            case CharType.AlphanumericUpper:
                return random.NextAlphanumericChar(true);
            case CharType.Numeric:
                return random.NextNumericChar();
            default:
                return random.NextAlphanumericChar();
        }
    }

    public static char NextChar(this Random random) {
        return random.NextChar(CharType.AlphanumericAny);
    }

    private static char NextAlphanumericChar(this Random random, bool uppercase) {
        bool numeric = random.NextBool(AlphanumericProbabilityNumericCased);

        if (numeric)
            return random.NextNumericChar();
        else
            return random.NextAlphabeticChar(uppercase);
    }

    private static char NextAlphanumericChar(this Random random) {
        bool numeric = random.NextBool(AlphanumericProbabilityNumericAny);

        if (numeric)
            return random.NextNumericChar();
        else
            return random.NextAlphabeticChar(random.NextBool());
    }

    private static char NextAlphabeticChar(this Random random, bool uppercase) {
        if (uppercase)
            return (char)random.Next(65, 91);
        else
            return (char)random.Next(97, 123);
    }

    private static char NextAlphabeticChar(this Random random) {
        return random.NextAlphabeticChar(random.NextBool());
    }

    private static char NextNumericChar(this Random random) {
        return (char)random.Next(48, 58);
    }

    public static DateTime NextDateTime(this Random random, DateTime minValue, DateTime maxValue) {
        return DateTime.FromOADate(
            random.NextDouble(minValue.ToOADate(), maxValue.ToOADate())
        );
    }

    public static DateTime NextDateTime(this Random random) {
        return random.NextDateTime(DateTime.MinValue, DateTime.MaxValue);
    }

    public static double NextDouble(this Random random, double minValue, double maxValue) {
        if (maxValue < minValue)
            throw new ArgumentException("Minimum value must be less than maximum value.");

        double difference = maxValue - minValue;
        if (!double.IsInfinity(difference))
            return minValue + (random.NextDouble() * difference);

        else {
            // to avoid evaluating to Double.Infinity, we split the range into two halves:
            double halfDifference = (maxValue * 0.5) - (minValue * 0.5);

            // 50/50 chance of returning a value from the first or second half of the range
            if (random.NextBool())
                return minValue + (random.NextDouble() * halfDifference);
            else
                return (minValue + halfDifference) + (random.NextDouble() * halfDifference);
        }
    }

    public static string NextString(this Random random, int numChars, CharType mode) {
        char[] chars = new char[numChars];

        for (int i = 0; i < numChars; ++i)
            chars[i] = random.NextChar(mode);

        return new string(chars);
    }

    public static string NextString(this Random random, int numChars) {
        return random.NextString(numChars, CharType.AlphanumericAny);
    }

    public static TimeSpan NextTimeSpan(this Random random, TimeSpan minValue, TimeSpan maxValue) {
        return TimeSpan.FromMilliseconds(
            random.NextDouble(minValue.TotalMilliseconds, maxValue.TotalMilliseconds)
        );
    }

    public static TimeSpan NextTimeSpan(this Random random) {
        return random.NextTimeSpan(TimeSpan.MinValue, TimeSpan.MaxValue);
    }
}


IEnumerable<>洗牌

我用Fisher-Yates算法实现了一个shuffle函数。

通过使用yield return并将代码分成两个函数,实现了正确的参数验证和延迟执行。(谢谢,丹,在我的第一个版本中指出了这个缺陷)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
static public IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
{
    if (source == null) throw new ArgumentNullException("source");

    return ShuffleIterator(source);
}

static private IEnumerable<T> ShuffleIterator<T>(this IEnumerable<T> source)
{
    T[] array = source.ToArray();
    Random rnd = new Random();          
    for (int n = array.Length; n > 1;)
    {
        int k = rnd.Next(n--); // 0 <= k < n

        //Swap items
        if (n != k)
        {
            T tmp = array[k];
            array[k] = array[n];
            array[n] = tmp;
        }
    }

    foreach (var item in array) yield return item;
}


另一个对我有用的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/// <summary>
/// Converts any type in to an Int32
/// </summary>
/// <typeparam name="T">Any Object</typeparam>
/// <param name="value">Value to convert</param>
/// <returns>The integer, 0 if unsuccessful</returns>
public static int ToInt32<T>(this T value)
{
  int result;
  if (int.TryParse(value.ToString(), out result))
  {
    return result;
  }
  return 0;
}

/// <summary>
/// Converts any type in to an Int32 but if null then returns the default
/// </summary>
/// <param name="value">Value to convert</param>
/// <typeparam name="T">Any Object</typeparam>
/// <param name="defaultValue">Default to use</param>
/// <returns>The defaultValue if unsuccessful</returns>
public static int ToInt32<T>(this T value, int defaultValue)
{
  int result;
  if (int.TryParse(value.ToString(), out result))
  {
    return result;
  }
  return defaultValue;
}

例子:

1
int number ="123".ToInt32();

或:

1
int badNumber ="a".ToInt32(100); // Returns 100 since a is nan


我很失望.NET框架更喜欢将文件和目录表示为字符串而不是对象,而且fileinfo和directoryinfo类型没有我希望的那样强大。因此,我开始根据需要编写流畅的扩展方法,例如:

1
2
3
4
5
6
7
8
9
public static FileInfo SetExtension(this FileInfo fileInfo, string extension)
{
    return new FileInfo(Path.ChangeExtension(fileInfo.FullName, extension));
}

public static FileInfo SetDirectory(this FileInfo fileInfo, string directory)
{
    return new FileInfo(Path.Combine(directory, fileInfo.Name));
}

是的,你可以把这个放到密码丛里


我的一些最好的方法扩展(我有很多!):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static T ToEnum<T>(this string str) where T : struct
{
    return (T)Enum.Parse(typeof(T), str);
}

//DayOfWeek sunday = "Sunday".ToEnum<DayOfWeek>();

public static string ToString<T>(this IEnumerable<T> collection, string separator)
{
    return ToString(collection, t => t.ToString(), separator);
}

public static string ToString<T>(this IEnumerable<T> collection, Func<T, string> stringElement, string separator)
{
    StringBuilder sb = new StringBuilder();
    foreach (var item in collection)
    {
        sb.Append(stringElement(item));
        sb.Append(separator);
    }
    return sb.ToString(0, Math.Max(0, sb.Length - separator.Length));  // quita el ultimo separador
}

//new []{1,2,3}.ToString(i=>i*2,",")  -->"2, 4, 6"

另外,下一个变量在几乎任何情况下都可以在同一行中继续运行,不需要声明新的变量,然后删除状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
public static R Map<T, R>(this T t, Func<T, R> func)
{
    return func(t);
}

ExpensiveFindWally().Map(wally=>wally.FirstName +"" + wally.LastName)

public static R TryCC<T, R>(this T t, Func<T, R> func)
    where T : class
    where R : class
{
    if (t == null) return null;
    return func(t);
}

public static R? TryCS<T, R>(this T t, Func<T, R> func)
    where T : class
    where R : struct
{
    if (t == null) return null;
    return func(t);
}

public static R? TryCS<T, R>(this T t, Func<T, R?> func)
    where T : class
    where R : struct
{
    if (t == null) return null;
    return func(t);
}

public static R TrySC<T, R>(this T? t, Func<T, R> func)
    where T : struct
    where R : class
{
    if (t == null) return null;
    return func(t.Value);
}

public static R? TrySS<T, R>(this T? t, Func<T, R> func)
    where T : struct
    where R : struct
{
    if (t == null) return null;
    return func(t.Value);
}

public static R? TrySS<T, R>(this T? t, Func<T, R?> func)
    where T : struct
    where R : struct
{
    if (t == null) return null;
    return func(t.Value);
}

//int? bossNameLength =  Departament.Boss.TryCC(b=>b.Name).TryCS(s=>s.Length);


public static T ThrowIfNullS<T>(this T? t, string mensaje)
    where T : struct
{
    if (t == null)
        throw new NullReferenceException(mensaje);
    return t.Value;
}

public static T ThrowIfNullC<T>(this T t, string mensaje)
    where T : class
{
    if (t == null)
        throw new NullReferenceException(mensaje);
    return t;
}

public static T Do<T>(this T t, Action<T> action)
{
    action(t);
    return t;
}

//Button b = new Button{Content ="Click"}.Do(b=>Canvas.SetColumn(b,2));

public static T TryDo<T>(this T t, Action<T> action) where T : class
{
    if (t != null)
        action(t);
    return t;
}

public static T? TryDoS<T>(this T? t, Action<T> action) where T : struct
{
    if (t != null)
        action(t.Value);
    return t;
}

希望它看起来不像来自火星。)


与时间跨度相关的扩展,如:

1
2
3
4
5
6
7
8
9
public static TimeSpan Seconds(this int seconds)
{
  return TimeSpan.FromSeconds(seconds);
}

public static TimeSpan Minutes(this int minutes)
{
  return TimeSpan.FromMinutes(minutes);
}

允许使用:

1
2
1.Seconds()
20.Minutes()

锁定扩展名,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static IDisposable GetReadLock(this ReaderWriterLockSlim slimLock)
{
  slimLock.EnterReadLock();
  return new DisposableAction(slimLock.ExitReadLock);
}

public static IDisposable GetWriteLock(this ReaderWriterLockSlim slimLock)
{
  slimLock.EnterWriteLock();
  return new DisposableAction(slimLock.ExitWriteLock);
}

public static IDisposable GetUpgradeableReadLock(this ReaderWriterLockSlim slimLock)
{
  slimLock.EnterUpgradeableReadLock();
  return new DisposableAction(slimLock.ExitUpgradeableReadLock);
}

允许使用如下锁:

1
2
3
4
5
6
7
8
using (lock.GetUpgradeableReadLock())
{
  // try read
  using (lock.GetWriteLock())
  {
    //do write
  }
}

还有许多其他来自Lokad共享图书馆的


我在我的Silverlight项目中使用这些:

1
2
3
4
5
6
7
8
9
public static void Show(this UIElement element)
{
    element.Visibility = Visibility.Visible;
}

public static void Hide(this UIElement element)
{
    element.Visibility = Visibility.Collapsed;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public static class EnumerableExtensions
{
    [Pure]
    public static U MapReduce<T, U>(this IEnumerable<T> enumerable, Func<T, U> map, Func<U, U, U> reduce)
    {
        CodeContract.RequiresAlways(enumerable != null);
        CodeContract.RequiresAlways(enumerable.Skip(1).Any());
        CodeContract.RequiresAlways(map != null);
        CodeContract.RequiresAlways(reduce != null);
        return enumerable.AsParallel().Select(map).Aggregate(reduce);
    }
    [Pure]
    public static U MapReduce<T, U>(this IList<T> list, Func<T, U> map, Func<U, U, U> reduce)
    {
        CodeContract.RequiresAlways(list != null);
        CodeContract.RequiresAlways(list.Count >= 2);
        CodeContract.RequiresAlways(map != null);
        CodeContract.RequiresAlways(reduce != null);
        U result = map(list[0]);
        for (int i = 1; i < list.Count; i++)
        {
            result = reduce(result,map(list[i]));
        }
        return result;
    }

    //Parallel version; creates garbage
    [Pure]
    public static U MapReduce<T, U>(this IList<T> list, Func<T, U> map, Func<U, U, U> reduce)
    {
        CodeContract.RequiresAlways(list != null);
        CodeContract.RequiresAlways(list.Skip(1).Any());
        CodeContract.RequiresAlways(map != null);
        CodeContract.RequiresAlways(reduce != null);

        U[] mapped = new U[list.Count];
        Parallel.For(0, mapped.Length, i =>
            {
                mapped[i] = map(list[i]);
            });
        U result = mapped[0];
        for (int i = 1; i < list.Count; i++)
        {
            result = reduce(result, mapped[i]);
        }
        return result;
    }

}


一些日期函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static bool IsFuture(this DateTime date, DateTime from)
{
    return date.Date > from.Date;
}

public static bool IsFuture(this DateTime date)
{
    return date.IsFuture(DateTime.Now);
}

public static bool IsPast(this DateTime date, DateTime from)
{
    return date.Date < from.Date;
}

public static bool IsPast(this DateTime date)
{
    return date.IsPast(DateTime.Now);
}


到目前为止,我只浏览了这4页,我很惊讶地发现,我没有看到这种方法来缩短InvokeRequired的支票:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
using System;
using System.Windows.Forms;

/// <summary>
/// Extension methods acting on Control objects.
/// </summary>
internal static class ControlExtensionMethods
{
    /// <summary>
    /// Invokes the given action on the given control's UI thread, if invocation is needed.
    /// </summary>
    /// <param name="control">Control on whose UI thread to possibly invoke.</param>
    /// <param name="action">Action to be invoked on the given control.</param>
    public static void MaybeInvoke(this Control control, Action action)
    {
        if (control != null && control.InvokeRequired)
        {
            control.Invoke(action);
        }
        else
        {
            action();
        }
    }

    /// <summary>
    /// Maybe Invoke a Func that returns a value.
    /// </summary>
    /// <typeparam name="T">Return type of func.</typeparam>
    /// <param name="control">Control on which to maybe invoke.</param>
    /// <param name="func">Function returning a value, to invoke.</param>
    /// <returns>The result of the call to func.</returns>
    public static T MaybeInvoke<T>(this Control control, Func<T> func)
    {
        if (control != null && control.InvokeRequired)
        {
            return (T)(control.Invoke(func));
        }
        else
        {
            return func();
        }
    }
}

用途:

1
2
3
4
myForm.MaybeInvoke(() => this.Text ="Hello world");

// Sometimes the control might be null, but that's okay.
var dialogResult = this.Parent.MaybeInvoke(() => MessageBox.Show(this,"Yes or no?","Choice", MessageBoxButtons.YesNo));

有时用自定义分隔符在列表中的选定元素上写出字符串很方便。

例如,如果您有一个List,并且想要循环使用逗号分隔的姓氏,您可以这样做。

1
2
3
4
5
6
string result = string.Empty;
foreach (var person in personList) {
   result += person.LastName +",";
}
result = result.Substring(0, result.Length - 2);
return result;

或者你可以使用这个方便的扩展方法

1
2
3
4
public static string Join<T>(this IEnumerable<T> collection, Func<T, string> func, string separator)
{
  return String.Join(separator, collection.Select(func).ToArray());
}

像这样使用

1
personList.Join(x => x.LastName,",");

它产生相同的结果,在本例中是一个用逗号分隔的姓氏列表。


Hth.这些是我的主要作品。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;

namespace Insert.Your.Namespace.Here.Helpers
{
    public static class Extensions
    {
        public static bool IsNullOrEmpty<T>(this IEnumerable<T> iEnumerable)
        {
            // Cheers to Joel Mueller for the bugfix. Was .Count(), now it's .Any()
            return iEnumerable == null ||
                   !iEnumerable.Any();
        }

        public static IList<T> ToListIfNotNullOrEmpty<T>(this IList<T> iList)
        {
            return iList.IsNullOrEmpty() ? null : iList;
        }

        public static PagedList<T> ToPagedListIfNotNullOrEmpty<T>(this PagedList<T> pagedList)
        {
            return pagedList.IsNullOrEmpty() ? null : pagedList;
        }

        public static string ToPluralString(this int value)
        {
            return value == 1 ? string.Empty :"s";
        }

        public static string ToReadableTime(this DateTime value)
        {
            TimeSpan span = DateTime.Now.Subtract(value);
            const string plural ="s";


            if (span.Days > 7)
            {
                return value.ToShortDateString();
            }

            switch (span.Days)
            {
                case 0:
                    switch (span.Hours)
                    {
                        case 0:
                            if (span.Minutes == 0)
                            {
                                return span.Seconds <= 0
                                           ?"now"
                                           : string.Format("{0} second{1} ago",
                                                           span.Seconds,
                                                           span.Seconds != 1 ? plural : string.Empty);
                            }
                            return string.Format("{0} minute{1} ago",
                                                 span.Minutes,
                                                 span.Minutes != 1 ? plural : string.Empty);
                        default:
                            return string.Format("{0} hour{1} ago",
                                                 span.Hours,
                                                 span.Hours != 1 ? plural : string.Empty);
                    }
                default:
                    return string.Format("{0} day{1} ago",
                                         span.Days,
                                         span.Days != 1 ? plural : string.Empty);
            }
        }

        public static string ToShortGuidString(this Guid value)
        {
            return Convert.ToBase64String(value.ToByteArray())
                .Replace("/","_")
                .Replace("+","-")
                .Substring(0, 22);
        }

        public static Guid FromShortGuidString(this string value)
        {
            return new Guid(Convert.FromBase64String(value.Replace("_","/")
                                                         .Replace("-","+") +"=="));
        }

        public static string ToStringMaximumLength(this string value, int maximumLength)
        {
            return ToStringMaximumLength(value, maximumLength,"...");
        }

        public static string ToStringMaximumLength(this string value, int maximumLength, string postFixText)
        {
            if (string.IsNullOrEmpty(postFixText))
            {
                throw new ArgumentNullException("postFixText");
            }

            return value.Length > maximumLength
                       ? string.Format(CultureInfo.InvariantCulture,
                                      "{0}{1}",
                                       value.Substring(0, maximumLength - postFixText.Length),
                                       postFixText)
                       :
                           value;
        }

        public static string SlugDecode(this string value)
        {
            return value.Replace("_","");
        }

        public static string SlugEncode(this string value)
        {
            return value.Replace("","_");
        }
    }
}


二进制搜索:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public static T BinarySearch<T, TKey>(this IList<T> list, Func<T, TKey> keySelector, TKey key)
        where TKey : IComparable<TKey>
{
    int min = 0;
    int max = list.Count;
    int index = 0;
    while (min < max)
    {
        int mid = (max + min) / 2;
        T midItem = list[mid];
        TKey midKey = keySelector(midItem);
        int comp = midKey.CompareTo(key);
        if (comp < 0)
        {
            min = mid + 1;
        }
        else if (comp > 0)
        {
            max = mid - 1;
        }
        else
        {
            return midItem;
        }
    }
    if (min == max &&
        keySelector(list[min]).CompareTo(key) == 0)
    {
        return list[min];
    }
    throw new InvalidOperationException("Item not found");
}

用法(假设列表按ID排序):

1
var item = list.BinarySearch(i => i.Id, 42);

它抛出一个InvalidOperationException这个事实可能看起来很奇怪,但这是可枚举的,首先在没有匹配项的情况下执行。


字典的pythonic方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/// <summary>
/// If a key exists in a dictionary, return its value,
/// otherwise return the default value for that type.
/// </summary>
public static U GetWithDefault<T, U>(this Dictionary<T, U> dict, T key)
{
    return dict.GetWithDefault(key, default(U));
}

/// <summary>
/// If a key exists in a dictionary, return its value,
/// otherwise return the provided default value.
/// </summary>
public static U GetWithDefault<T, U>(this Dictionary<T, U> dict, T key, U defaultValue)
{
    return dict.ContainsKey(key)
        ? dict[key]
        : defaultValue;
}

用于在文件名中附加时间戳以确保唯一性。

1
2
3
4
5
6
7
8
9
/// <summary>
/// Format a DateTime as a string that contains no characters
//// that are banned from filenames, such as ':'.
/// </summary>
/// <returns>YYYY-MM-DD_HH.MM.SS</returns>
public static string ToFilenameString(this DateTime dt)
{
    return dt.ToString("s").Replace(":",".").Replace('T', '_');
}


我发现自己一次又一次地做这个…

1
2
3
4
public static bool EqualsIgnoreCase(this string a, string b)
{
    return string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
}

…接着是StartsWithIgnoreCaseEndsWithIgnoreCaseContainsIgnoreCase


函数通过操作系统文件系统信息比较文件/目录。这对于比较共享和本地文件很有用。

用途:

1
2
3
4
5
DirectoryInfo dir = new DirectoryInfo(@"C:\test\myShareDir");
Console.WriteLine(dir.IsSameFileAs(@"\\myMachineName\myShareDir"));

FileInfo file = new FileInfo(@"C:\test\myShareDir\file.txt");
Console.WriteLine(file.IsSameFileAs(@"\\myMachineName\myShareDir\file.txt"));

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public static class FileExtensions
{
    struct BY_HANDLE_FILE_INFORMATION
    {
        public uint FileAttributes;
        public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime;
        public uint VolumeSerialNumber;
        public uint FileSizeHigh;
        public uint FileSizeLow;
        public uint NumberOfLinks;
        public uint FileIndexHigh;
        public uint FileIndexLow;
    }

    //
    // CreateFile constants
    //
    const uint FILE_SHARE_READ = 0x00000001;
    const uint OPEN_EXISTING = 3;
    const uint GENERIC_READ = (0x80000000);
    const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;


    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr CreateFile(
        string lpFileName,
        uint dwDesiredAccess,
        uint dwShareMode,
        IntPtr lpSecurityAttributes,
        uint dwCreationDisposition,
        uint dwFlagsAndAttributes,
        IntPtr hTemplateFile);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool GetFileInformationByHandle(IntPtr hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation);

    public static bool IsSameFileAs(this FileSystemInfo file, string path)
    {
        BY_HANDLE_FILE_INFORMATION fileInfo1, fileInfo2;
        IntPtr ptr1 = CreateFile(file.FullName, GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero);
        if ((int)ptr1 == -1)
        {
            System.ComponentModel.Win32Exception e = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
            throw e;
        }
        IntPtr ptr2 = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero);
        if ((int)ptr2 == -1)
        {
            System.ComponentModel.Win32Exception e = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
            throw e;
        }
        GetFileInformationByHandle(ptr1, out fileInfo1);
        GetFileInformationByHandle(ptr2, out fileInfo2);

        return ((fileInfo1.FileIndexHigh == fileInfo2.FileIndexHigh) &&
            (fileInfo1.FileIndexLow == fileInfo2.FileIndexLow));
    }
}


使用键为字符串的字典时,使用不区分大小写的搜索返回现有键。我们的用例用于文件路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/// <summary>
/// Gets the key using <paramref name="caseInsensitiveKey"/> from <paramref name="dictionary"/>.
/// </summary>
/// <typeparam name="T">The dictionary value.</typeparam>
/// <param name="dictionary">The dictionary.</param>
/// <param name="caseInsensitiveKey">The case insensitive key.</param>
/// <returns>
/// An existing key; or <see cref="string.Empty"/> if not found.
/// </returns>
public static string GetKeyIgnoringCase<T>(this IDictionary<string, T> dictionary, string caseInsensitiveKey)
{
    if (string.IsNullOrEmpty(caseInsensitiveKey)) return string.Empty;
    foreach (string key in dictionary.Keys)
    {
        if (key.Equals(caseInsensitiveKey, StringComparison.InvariantCultureIgnoreCase))
        {
            return key;
        }
    }
    return string.Empty;
}


我通常使用匿名类型的扩展方法来获取字典ala ruby

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static Dictionary<string, object> ToDictionary(this object o)
{
    var dictionary = new Dictionary<string, object>();

    foreach (var propertyInfo in o.GetType().GetProperties())
    {
        if (propertyInfo.GetIndexParameters().Length == 0)
        {
            dictionary.Add(propertyInfo.Name, propertyInfo.GetValue(o, null));
        }
    }

    return dictionary;
}

你可以用它

1
2
var dummy = new { color ="#000000", width ="100%", id ="myid" };
Dictionary<string, object> dict = dummy.ToDictionary();

用扩展方法

1
2
3
4
5
6
7
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
    foreach (T item in source)
    {
        action(item);
    }
}

你可以做到

1
dummy.ToDictionary().ForEach((p) => Console.Write("{0}='{1}'", p.Key, p.Value));

产量

color='000000'width='100%'id='myid'


这是另一双,我发现它有着无穷的用途:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public static T ObjectWithMin<T, TResult>(this IEnumerable<T> sequence, Func<T, TResult> predicate)
    where T : class
    where TResult : IComparable
{
    if (!sequence.Any()) return null;

    //get the first object with its predicate value
    var seed = sequence.Select(x => new {Object = x, Value = predicate(x)}).FirstOrDefault();
    //compare against all others, replacing the accumulator with the lesser value
    //tie goes to first object found
    return
        sequence.Select(x => new {Object = x, Value = predicate(x)})
            .Aggregate(seed,(acc, x) => acc.Value.CompareTo(x.Value) <= 0 ? acc : x).Object;
}

public static T ObjectWithMax<T, TResult>(this IEnumerable<T> sequence, Func<T, TResult> predicate)
    where T : class
    where TResult : IComparable
{
    if (!sequence.Any()) return null;

    //get the first object with its predicate value
    var seed = sequence.Select(x => new {Object = x, Value = predicate(x)}).FirstOrDefault();
    //compare against all others, replacing the accumulator with the greater value
    //tie goes to last object found
    return
        sequence.Select(x => new {Object = x, Value = predicate(x)})
            .Aggregate(seed, (acc, x) => acc.Value.CompareTo(x.Value) > 0 ? acc : x).Object;
}

用途:

1
var myObject = myList.ObjectWithMin(x=>x.PropA);

这些方法基本上替代了像

1
var myObject = myList.OrderBy(x=>x.PropA).FirstOrDefault(); //O(nlog(n)) and unstable

1
var myObject = myList.Where(x=>x.PropA == myList.Min(x=>x.PropA)).FirstOrDefault(); //O(N^2) but stable

1
2
var minValue = myList.Min(x=>x.PropA);
var myObject = myList.Where(x=>x.PropA == minValue).FirstOrDefault(); //not a one-liner, and though linear and stable it's slower (evaluates the enumerable twice)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static string Format( this string str,
                    , params Expression<Func<string,object>>[] args)
{
    var parameters = args.ToDictionary
                        ( e=>string.Format("{{{0}}}",e.Parameters[0].Name)
                        , e=>e.Compile()(e.Parameters[0].Name));

    var sb = new StringBuilder(str);
    foreach(var kv in parameters)
    {
        sb.Replace( kv.Key
                  , kv.Value != null ? kv.Value.ToString() :"");
    }

    return sb.ToString();
}

通过上述扩展,您可以编写以下内容:

1
var str ="{foo} {bar} {baz}".Format(foo=>foo, bar=>2, baz=>new object());

然后你就可以得到"foo 2 System.Object


简单但比"Enumerable.Range"更好,imho:

1
2
3
4
5
6
7
8
9
10
/// <summary>
/// Replace"Enumerable.Range(n)" with"n.Range()":
/// </summary>
/// <param name="n">iterations</param>
/// <returns>0..n-1</returns>
public static IEnumerable<int> Range(this int n)
{
    for (int i = 0; i < n; i++)
        yield return i;
}


这里有一个位图扩展,可以将位图转换为灰度;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static Bitmap GrayScale(this Bitmap bitmap)
{
    Bitmap newBitmap = new Bitmap(bitmap.Width, bitmap.Height);
    Graphics g = Graphics.FromImage(newBitmap);

    //the grayscale ColorMatrix
    ColorMatrix colorMatrix = new ColorMatrix(new float[][] {
            new float[] {.3f, .3f, .3f, 0, 0},
            new float[] {.59f, .59f, .59f, 0, 0},
            new float[] {.11f, .11f, .11f, 0, 0},
            new float[] {0, 0, 0, 1, 0},
            new float[] {0, 0, 0, 0, 1}
    });

    ImageAttributes attributes = new ImageAttributes();
    attributes.SetColorMatrix(colorMatrix);
    g.DrawImage(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height), 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, attributes);
    g.Dispose();
    return newBitmap;
}

样品使用情况:

1
Bitmap grayscaled = bitmap.GrayScale()


这里有一个有趣的代码库在工作。在工作线程上执行一个昂贵的、懒惰的、可枚举的eval,并将结果推回到可观察的状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static IObservable<T> ToAsyncObservable<T>(this IEnumerable<T> @this)
{
    return Observable.Create<T>(observer =>
    {
        var task = new Task(() =>
        {
            try
            {
                @this.Run(observer.OnNext);
                observer.OnCompleted();
            }
            catch (Exception e)
            {
                observer.OnError(e);
            }
        });

        task.Start();

        return () => { };
    });
}

愚蠢的样本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
new DirectoryInfo(@"c:\program files")
    .EnumerateFiles("*", SearchOption.AllDirectories)
    .ToAsyncObservable()
    .BufferWithTime(TimeSpan.FromSeconds(0.5))
    .ObserveOnDispatcher()
    .Subscribe(
        l => Console.WriteLine("{0} received", l.Count),
        () => Console.WriteLine("Done!"));

for (;;)
{
    Thread.Sleep(10);
    Dispatcher.PushFrame(new DispatcherFrame());
}

显然,如果您不使用出色的反应式扩展,那么这个扩展对您来说将是无用的!

感谢Richard在评论中的更新,这个扩展方法是不必要的。RX已经有了一个扩展方法"toobservable",需要一个时间表。用这个来代替!


您可能已经知道扩展方法的一个有趣用法是作为一种混合。有些扩展方法,如XmlSerializable,几乎污染了每一个类;而且对大多数类来说,它没有意义,如ThreadSqlConnection

一些功能应该显式地混合到想要它的类中。我提议对这种类型使用一个新的符号,前缀为M

那么,XmlSerializable是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface MXmlSerializable { }
public static class XmlSerializable {
  public static string ToXml(this MXmlSerializable self) {
    if (self == null) throw new ArgumentNullException();
    var serializer = new XmlSerializer(self.GetType());
    using (var writer = new StringWriter()) {
      serializer.Serialize(writer, self);
      return writer.GetStringBuilder().ToString();
    }
  }
  public static T FromXml<T>(string xml) where T : MXmlSerializable {
    var serializer = new XmlSerializer(typeof(T));
    return (T)serializer.Deserialize(new StringReader(xml));
  }
}

然后一个类将其混合到:

1
2
3
4
public class Customer : MXmlSerializable {
  public string Name { get; set; }
  public bool Preferred { get; set; }
}

其用法很简单:

1
2
3
4
var customer = new Customer {
  Name ="Guybrush Threepwood",
  Preferred = true };
var xml = customer.ToXml();

如果您喜欢这个想法,您可以在项目中为有用的mixin创建一个新的名称空间。你怎么认为?

哦,顺便说一下,我认为大多数扩展方法都应该显式地测试空值。


我不想添加任何已经说过的内容,所以这里有一些我使用的,但没有提到。(很抱歉,如果时间过长):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public static class MyExtensions
{
    public static bool IsInteger(this string input)
    {
        int temp;

        return int.TryParse(input, out temp);
    }

    public static bool IsDecimal(this string input)
    {
        decimal temp;

        return decimal.TryParse(input, out temp);
    }

    public static int ToInteger(this string input, int defaultValue)
    {
        int temp;

        return (int.TryParse(input, out temp)) ? temp : defaultValue;
    }

    public static decimal ToDecimal(this string input, decimal defaultValue)
    {
        decimal temp;

        return (decimal.TryParse(input, out temp)) ? temp : defaultValue;
    }

    public static DateTime ToFirstOfTheMonth(this DateTime input)
    {
        return input.Date.AddDays(-1 * input.Day + 1);
    }

    // Intentionally returns 0 if the target date is before the input date.
    public static int MonthsUntil(this DateTime input, DateTime targetDate)
    {
        input = input.ToFirstOfTheMonth();

        targetDate = targetDate.ToFirstOfTheMonth();

        int result = 0;

        while (input < targetDate)
        {
        input = input.AddMonths(1);
            result++;
        }

        return result;
    }

    // Used for backwards compatibility in a system built before my time.
    public static DataTable ToDataTable(this IEnumerable input)
    {
        // too much code to show here right now...
    }
}

String.As,可用于将字符串值转换为某种类型(主要用于支持IConvertable的基元和类型)。适用于Nullable类型甚至Enums!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
public static partial class StringExtensions
{
    /// <summary>
    /// Converts the string to the specified type, using the default value configured for the type.
    /// </summary>
    /// <typeparam name="T">Type the string will be converted to. The type must implement IConvertable.</typeparam>
    /// <param name="original">The original string.</param>
    /// <returns>The converted value.</returns>
    public static T As<T>(this String original)
    {
        return As(original, CultureInfo.CurrentCulture,
                  default(T));
    }

    /// <summary>
    /// Converts the string to the specified type, using the default value configured for the type.
    /// </summary>
    /// <typeparam name="T">Type the string will be converted to.</typeparam>
    /// <param name="original">The original string.</param>
    /// <param name="defaultValue">The default value to use in case the original string is null or empty, or can't be converted.</param>
    /// <returns>The converted value.</returns>
    public static T As<T>(this String original, T defaultValue)
    {
        return As(original, CultureInfo.CurrentCulture, defaultValue);
    }

    /// <summary>
    /// Converts the string to the specified type, using the default value configured for the type.
    /// </summary>
    /// <typeparam name="T">Type the string will be converted to.</typeparam>
    /// <param name="original">The original string.</param>
    /// <param name="provider">Format provider used during the type conversion.</param>
    /// <returns>The converted value.</returns>
    public static T As<T>(this String original, IFormatProvider provider)
    {
        return As(original, provider, default(T));
    }

    /// <summary>
    /// Converts the string to the specified type.
    /// </summary>
    /// <typeparam name="T">Type the string will be converted to.</typeparam>
    /// <param name="original">The original string.</param>
    /// <param name="provider">Format provider used during the type conversion.</param>
    /// <param name="defaultValue">The default value to use in case the original string is null or empty, or can't be converted.</param>
    /// <returns>The converted value.</returns>
    /// <remarks>
    /// If an error occurs while converting the specified value to the requested type, the exception is caught and the default is returned. It is strongly recommended you
    /// do NOT use this method if it is important that conversion failures are not swallowed up.
    ///
    /// This method is intended to be used to convert string values to primatives, not for parsing, converting, or deserializing complex types.
    /// </remarks>
    public static T As<T>(this String original, IFormatProvider provider,
                          T defaultValue)
    {
        T result;
        Type type = typeof (T);

        if (String.IsNullOrEmpty(original)) result = defaultValue;
        else
        {
            // need to get the underlying type if T is Nullable<>.

            if (type.IsNullableType())
            {
                type = Nullable.GetUnderlyingType(type);
            }

            try
            {
                // ChangeType doesn't work properly on Enums
                result = type.IsEnum
                             ? (T) Enum.Parse(type, original, true)
                             : (T) Convert.ChangeType(original, type, provider);
            }
            catch // HACK: what can we do to minimize or avoid raising exceptions as part of normal operation? custom string parsing (regex?) for well-known types? it would be best to know if you can convert to the desired type before you attempt to do so.
            {
                result = defaultValue;
            }
        }

        return result;
    }
}

这依赖于对Type的另一个简单扩展:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/// <summary>
/// Extension methods for <see cref="Type"/>.
/// </summary>
public static class TypeExtensions
{
    /// <summary>
    /// Returns whether or not the specified type is <see cref="Nullable{T}"/>.
    /// </summary>
    /// <param name="type">A <see cref="Type"/>.</param>
    /// <returns>True if the specified type is <see cref="Nullable{T}"/>; otherwise, false.</returns>
    /// <remarks>Use <see cref="Nullable.GetUnderlyingType"/> to access the underlying type.</remarks>
    public static bool IsNullableType(this Type type)
    {
        if (type == null) throw new ArgumentNullException("type");

        return type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof (Nullable<>));
    }
}

用途:

1
2
3
4
5
var someInt ="1".As<int>();
var someIntDefault ="bad value".As(1); //"bad value" won't convert, so the default value 1 is returned.
var someEnum ="Sunday".As<DayOfWeek>();
someEnum ="0".As<DayOfWeek>(); // returns Sunday
var someNullableEnum ="".As<DayOfWeek?>(null); // returns a null value since"" can't be converted

我发现以下扩展方法非常有用:

1
2
3
4
public static T GetService<T>(this IServiceProvider provider)
{
    return (T)provider.GetService(typeof(T));
}

它使得使用IServiceProvider接口更加容易。比较:

1
IProvideValueTarget target = (IProvideValueTarget)serviceProvider(typeof(IProvideValueTarget));

1
var target = serviceProvider.GetService<IProvideValueTarget>();

我创建了一个不错的每个扩展,它的行为与jquery的每个函数相同。

它允许类似于下面的内容,您可以从中获取当前值的索引,并通过返回false脱离循环:

1
2
3
4
5
6
7
new[] {"first","second","third" }.Each((value, index) =>
{
    if (value.Contains("d"))
        return false;
    Console.Write(value);
    return true;
});

下面是代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/// <summary>
/// Generic iterator function that is useful to replace a foreach loop with at your discretion.  A provided action is performed on each element.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="action">Function that takes in the current value in the sequence.
/// <returns></returns>
public static IEnumerable<T> Each<T>(this IEnumerable<T> source, Action<T> action)
{
    return source.Each((value, index) =>
    {
        action(value);
        return true;
    });
}


/// <summary>
/// Generic iterator function that is useful to replace a foreach loop with at your discretion.  A provided action is performed on each element.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="action">Function that takes in the current value and its index in the sequence.  
/// <returns></returns>
public static IEnumerable<T> Each<T>(this IEnumerable<T> source, Action<T, int> action)
{
    return source.Each((value, index) =>
    {
        action(value, index);
        return true;
    });
}

/// <summary>
/// Generic iterator function that is useful to replace a foreach loop with at your discretion.  A provided action is performed on each element.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="action">Function that takes in the current value in the sequence.  Returns a value indicating whether the iteration should continue.  So return false if you don't want to iterate anymore.</param>
/// <returns></returns>
public static IEnumerable<T> Each<T>(this IEnumerable<T> source, Func<T, bool> action)
{
    return source.Each((value, index) =>
    {
        return action(value);
    });
}

/// <summary>
/// Generic iterator function that is useful to replace a foreach loop with at your discretion.  A provided action is performed on each element.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="action">Function that takes in the current value and its index in the sequence.  Returns a value indicating whether the iteration should continue.  So return false if you don't want to iterate anymore.</param>
/// <returns></returns>
public static IEnumerable<T> Each<T>(this IEnumerable<T> source, Func<T, int, bool> action)
{
    if (source == null)
        return source;

    int index = 0;
    foreach (var sourceItem in source)
    {
        if (!action(sourceItem, index))
            break;
        index++;
    }
    return source;
}


我经常在可以为空的数字上使用这个。我帮助捕捉0,Nan,无穷大的除法…

1
2
3
4
5
public static bool IsNullOrDefault<T>(this T? o)
    where T : struct
{
        return o == null || o.Value.Equals(default(T));
}


事实上,我今天刚写了这个博客。它是一个围绕INotifyPropertyChanged属性的强类型反应性包装器。

GetPropertyValues返回值的IObservable,从当前值开始。如果忽略当前值,则可以对结果调用Skip(1)

用法如下:

1
IObservable<int> values = viewModel.GetPropertyValues(x => x.IntProperty);

实施:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public static class NotifyPropertyChangeReactiveExtensions
{
    // Returns the values of property (an Expression) as they change,
    // starting with the current value
    public static IObservable<TValue> GetPropertyValues<TSource, TValue>(
        this TSource source, Expression<Func<TSource, TValue>> property)
        where TSource : INotifyPropertyChanged
    {
        MemberExpression memberExpression = property.Body as MemberExpression;

        if (memberExpression == null)
        {
            throw new ArgumentException(
               "property must directly access a property of the source");
        }

        string propertyName = memberExpression.Member.Name;

        Func<TSource, TValue> accessor = property.Compile();

        return source.GetPropertyChangedEvents()
            .Where(x => x.EventArgs.PropertyName == propertyName)
            .Select(x => accessor(source))
            .StartWith(accessor(source));
    }

    // This is a wrapper around FromEvent(PropertyChanged)
    public static IObservable<IEvent<PropertyChangedEventArgs>>
        GetPropertyChangedEvents(this INotifyPropertyChanged source)
    {
        return Observable.FromEvent<PropertyChangedEventHandler,
            PropertyChangedEventArgs>(
            h => new PropertyChangedEventHandler(h),
            h => source.PropertyChanged += h,
            h => source.PropertyChanged -= h);
    }
}

我的建议是:

1
2
3
4
public static bool IsNullOrEmpty(this ICollection obj)
{
  return (obj == null || obj.Count == 0);
}

使用集合和数组:

1
bool isNullOrEmpty = array.IsNullOrEmpty()

而不是

1
bool isNullOrEmpty = array == null || array.Length == 0;


这些扩展方法异步调用事件。他们受到这个堆积如山的答案的启发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/// <summary>
/// Invoke an event asynchronously. Each subscriber to the event will be invoked on a separate thread.
/// </summary>
/// <param name="someEvent">The event to be invoked asynchronously.</param>
/// <param name="sender">The sender of the event.</param>
/// <param name="args">The args of the event.</param>
/// <typeparam name="TEventArgs">The type of <see cref="EventArgs"/> to be used with the event.</typeparam>
public static void InvokeAsync<TEventArgs>(this EventHandler<TEventArgs> someEvent, object sender, TEventArgs args)
    where TEventArgs : EventArgs
{
    if (someEvent == null)
    {
        return;
    }

    var eventListeners = someEvent.GetInvocationList();

    AsyncCallback endAsyncCallback = delegate(IAsyncResult iar)
    {
        var ar = iar as AsyncResult;
        if (ar == null)
        {
            return;
        }

        var invokedMethod = ar.AsyncDelegate as EventHandler<TEventArgs>;
        if (invokedMethod != null)
        {
            invokedMethod.EndInvoke(iar);
        }
    };

    foreach (EventHandler<TEventArgs> methodToInvoke in eventListeners)
    {
        methodToInvoke.BeginInvoke(sender, args, endAsyncCallback, null);
    }
}

/// <summary>
/// Invoke an event asynchronously. Each subscriber to the event will be invoked on a separate thread.
/// </summary>
/// <param name="someEvent">The event to be invoked asynchronously.</param>
/// <param name="sender">The sender of the event.</param>
/// <param name="args">The args of the event.</param>
public static void InvokeAsync(this EventHandler someEvent, object sender, EventArgs args)
{
    if (someEvent == null)
    {
        return;
    }

    var eventListeners = someEvent.GetInvocationList();

    AsyncCallback endAsyncCallback = delegate(IAsyncResult iar)
    {
        var ar = iar as AsyncResult;
        if (ar == null)
        {
            return;
        }

        var invokedMethod = ar.AsyncDelegate as EventHandler;
        if (invokedMethod != null)
        {
            invokedMethod.EndInvoke(iar);
        }
    };

    foreach (EventHandler methodToInvoke in eventListeners)
    {
        methodToInvoke.BeginInvoke(sender, args, endAsyncCallback, null);
    }
}

使用:

1
2
3
4
5
6
7
8
9
public class Foo
{
    public event EventHandler<EventArgs> Bar;

    public void OnBar()
    {
        Bar.InvokeAsync(this, EventArgs.Empty);
    }
}

请注意,您不必在调用事件之前检查它是否为空。例如。:

1
2
3
4
5
EventHandler<EventArgs> handler = Bar;
if (handler != null)
{
    // Invoke the event
}

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void Main()
{
    EventHandler<EventArgs> handler1 =
    delegate(object sender, EventArgs args)
    {
        // Simulate performing work in handler1
        Thread.Sleep(100);
        Console.WriteLine("Handled 1");
    };

    EventHandler<EventArgs> handler2 =
    delegate(object sender, EventArgs args)
    {
        // Simulate performing work in handler2
        Thread.Sleep(50);
        Console.WriteLine("Handled 2");
    };

    EventHandler<EventArgs> handler3 =
    delegate(object sender, EventArgs args)
    {
        // Simulate performing work in handler3
        Thread.Sleep(25);
        Console.WriteLine("Handled 3");
    };

    var foo = new Foo();
    foo.Bar += handler1;
    foo.Bar += handler2;
    foo.Bar += handler3;
    foo.OnBar();

    Console.WriteLine("Start executing important stuff");

    // Simulate performing some important stuff here, where we don't want to
    // wait around for the event handlers to finish executing
    Thread.Sleep(1000);

    Console.WriteLine("Finished executing important stuff");
}

调用事件将(通常)生成此输出:

Start executing important stuff
Handled 3
Handled 2
Handled 1
Finished executing important stuff

如果事件是同步调用的,它将始终产生这个输出,并延迟"重要"内容的执行:

Handled 1
Handled 2
Handled 3
Start executing important stuff
Finished executing important stuff


将列表转换为数据表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public static class DataTableConverter
{
    /// <summary>
    /// Convert a List{T} to a DataTable.
    /// </summary>
    public static DataTable ToDataTable<T>(this IList<T> items)
    {
        var tb = new DataTable(typeof(T).Name);

        PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

        foreach (PropertyInfo prop in props)
        {
            Type t = GetCoreType(prop.PropertyType);
            tb.Columns.Add(prop.Name, t);
        }

        foreach (T item in items)
        {
            var values = new object[props.Length];

            for (int i = 0; i < props.Length; i++)
            {
                values[i] = props[i].GetValue(item, null);
            }

            tb.Rows.Add(values);
        }

        return tb;
    }

    /// <summary>
    /// Determine of specified type is nullable
    /// </summary>
    public static bool IsNullable(Type t)
    {
        return !t.IsValueType || (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>));
    }

    /// <summary>
    /// Return underlying type if type is Nullable otherwise return the type
    /// </summary>
    public static Type GetCoreType(Type t)
    {
        if (t != null && IsNullable(t))
        {
            if (!t.IsValueType)
            {
                return t;
            }
            else
            {
                return Nullable.GetUnderlyingType(t);
            }
        }
        else
        {
            return t;
        }
    }
}

用途:

1
2
    IList<MyClass> myClassList = new List<MyClass>();
    DataTable myClassDataTable = myClassList.ToDataTable();


我在我的Web项目中使用这些,主要是在MVC中。我有一些是为viewdata和tempdata编写的

1
2
3
4
5
6
7
8
9
10
11
12
13
/// <summary>
/// Checks the Request.QueryString for the specified value and returns it, if none
/// is found then the default value is returned instead
/// </summary>
public static T QueryValue<T>(this HtmlHelper helper, string param, T defaultValue) {
    object value = HttpContext.Current.Request.QueryString[param] as object;
    if (value == null) { return defaultValue; }
    try {
        return (T)Convert.ChangeType(value, typeof(T));
    } catch (Exception) {
        return defaultValue;
    }
}

这样我就可以写一些像…

1
2
3
4
5
6
7
<% if (Html.QueryValue("login", false)) { %>
    Welcome Back!

<% } else { %>
    <%-- Render the control or something --%>

<% } %>


我使用的两种颜色扩展,主要用于控制开发:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static class ColorExtensions
{
  // Gets a color that will be readable on top of a given background color
  public static Color GetForegroundColor(this Color input)
  {
    // Math taken from one of the replies to
    // http://stackoverflow.com/questions/2241447/make-foregroundcolor-black-or-white-depending-on-background
    if (Math.Sqrt(input.R * input.R * .241 + input.G * input.G * .691 + input.B * input.B * .068) > 128)
      return Color.Black;
    else
      return Color.White;
  }

  // Converts a given Color to gray
  public static Color ToGray(this Color input)
  {
    int g = (int)(input.R * .299) + (int)(input.G * .587) + (int)(input.B * .114);
    return Color.FromArgb(input.A, g, g, g);
  }
}

用途:

1
2
Color foreColor = someBackColor.GetForegroundColor();
Color grayColor = someBackColor.ToGray();

我一直觉得String类上的substring方法不够用。通常,当您执行子字符串时,您知道要从何处开始字符,以及要从何处结束字符。因此,我一直觉得必须指定长度作为第二个参数是愚蠢的。因此,我编写了自己的扩展方法。一个接受startindex和endindex的函数。第一种方法是,使用start text(字符串)和end text(字符串),这样您就可以指定子字符串从何处开始,以及子字符串从何处结束的文本。

注意:我无法将方法子字符串命名为.NET中的子字符串,因为我的第一个重载采用与.NET重载之一相同的参数类型。因此,我把它们命名为subsetString。请随意添加到codeplex…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public static class StringExtensions
{
    /// <summary>
    /// Returns a Subset string starting at the specified start index and ending and the specified end
    /// index.
    /// </summary>
    /// <param name="s">The string to retrieve the subset from.</param>
    /// <param name="startIndex">The specified start index for the subset.</param>
    /// <param name="endIndex">The specified end index for the subset.</param>
    /// <returns>A Subset string starting at the specified start index and ending and the specified end
    /// index.</returns>
    public static string Subsetstring(this string s, int startIndex, int endIndex)
    {
        if (startIndex > endIndex)
        {
            throw new InvalidOperationException("End Index must be after Start Index.");
        }

        if (startIndex < 0)
        {
            throw new InvalidOperationException("Start Index must be a positive number.");
        }

        if(endIndex <0)
        {
            throw new InvalidOperationException("End Index must be a positive number.");
        }

        return s.Substring(startIndex, (endIndex - startIndex));
    }

    /// <summary>
    /// Finds the specified Start Text and the End Text in this string instance, and returns a string
    /// containing all the text starting from startText, to the begining of endText. (endText is not
    /// included.)
    /// </summary>
    /// <param name="s">The string to retrieve the subset from.</param>
    /// <param name="startText">The Start Text to begin the Subset from.</param>
    /// <param name="endText">The End Text to where the Subset goes to.</param>
    /// <param name="ignoreCase">Whether or not to ignore case when comparing startText/endText to the string.</param>
    /// <returns>A string containing all the text starting from startText, to the begining of endText.</returns>
    public static string Subsetstring(this string s, string startText, string endText, bool ignoreCase)
    {
        if (string.IsNullOrEmpty(startText) || string.IsNullOrEmpty(endText))
        {
            throw new ArgumentException("Start Text and End Text cannot be empty.");
        }
        string temp = s;
        if (ignoreCase)
        {
            temp = s.ToUpperInvariant();
            startText = startText.ToUpperInvariant();
            endText = endText.ToUpperInvariant();
        }
        int start = temp.IndexOf(startText);
        int end = temp.IndexOf(endText, start);
        return Subsetstring(s, start, end);
    }
}

用途:

1
2
string s ="This is a tester for my cool extension method!!";
       s = s.Subsetstring("tester","cool",true);

输出:"我的测试仪"


没有检查整个线程,因此它可能已经存在,但:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public static class FluentOrderingExtensions
    public class FluentOrderer<T> : IEnumerable<T>
    {
        internal List<Comparison<T>> Comparers = new List<Comparison<T>>();

        internal IEnumerable<T> Source;

        public FluentOrderer(IEnumerable<T> source)
        {
            Source = source;
        }

        #region Implementation of IEnumerable

        public IEnumerator<T> GetEnumerator()
        {
            var workingArray = Source.ToArray();
            Array.Sort(workingArray, IterativeComparison);

            foreach(var element in workingArray) yield return element;
        }

        private int IterativeComparison(T a, T b)
        {
            foreach (var comparer in Comparers)
            {
                var result = comparer(a,b);
                if(result != 0) return result;
            }
            return 0;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion
    }

    public static FluentOrderer<T> OrderFluentlyBy<T,TResult>(this IEnumerable<T> source, Func<T,TResult> predicate)
        where TResult : IComparable<TResult>
    {
        var result = new FluentOrderer<T>(source);
        result.Comparers.Add((a,b)=>predicate(a).CompareTo(predicate(b)));
        return result;
    }

    public static FluentOrderer<T> OrderFluentlyByDescending<T,TResult>(this IEnumerable<T> source, Func<T,TResult> predicate)
        where TResult : IComparable<TResult>
    {
        var result = new FluentOrderer<T>(source);
        result.Comparers.Add((a,b)=>predicate(a).CompareTo(predicate(b)) * -1);
        return result;
    }

    public static FluentOrderer<T> ThenBy<T, TResult>(this FluentOrderer<T> source, Func<T, TResult> predicate)
        where TResult : IComparable<TResult>
    {
        source.Comparers.Add((a, b) => predicate(a).CompareTo(predicate(b)));
        return source;
    }

    public static FluentOrderer<T> ThenByDescending<T, TResult>(this FluentOrderer<T> source, Func<T, TResult> predicate)
        where TResult : IComparable<TResult>
    {
        source.Comparers.Add((a, b) => predicate(a).CompareTo(predicate(b)) * -1);
        return source;
    }
}

用途:

1
2
3
4
5
6
var myFluentlyOrderedList = GetABunchOfComplexObjects()
    .OrderFluentlyBy(x=>x.PropertyA)
    .ThenByDescending(x=>x.PropertyB)
    .ThenBy(x=>x.SomeMethod())
    .ThenBy(x=>SomeOtherMethodAppliedTo(x))
    .ToList();

…当然,假设所有谓词返回的类型都是自己可比较的。它可以更好地与稳定排序(如mergesort)一起使用,而不是.NET的内置Quicksort,但它提供了与SQL类似的可读多字段排序能力(无论如何,只要方法链可以获得)。通过定义采用比较lambda的重载,而不是基于谓词创建它,可以将此扩展为容纳不可IComparable的成员。

编辑:解释一下,因为注释器有一些正常运行:这组方法改进了基本的order by()功能,允许您按重要性的降序对多个字段进行排序。一个实际的例子是按客户对发票列表进行排序,然后按发票编号(或发票日期)进行排序。其他按此顺序获取数据的方法要么不起作用(orderby()使用了不稳定的排序,因此无法将其链接),要么效率低下,看起来不像您要做的那样。


如果有unix时间戳和iso 8601格式的日期和时间,那就太好了。大量用于网站和休息服务。

我在我的facebook库中使用它。您可以找到来源http://github.com/prabirshrestha/facebooksarp/blob/master/src/facebooksarp.core/facebookutils/dateutils.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private static readonly DateTime EPOCH = DateTime.SpecifyKind(new DateTime(1970, 1, 1, 0, 0, 0, 0),DateTimeKind.Utc);

public static DateTime FromUnixTimestamp(long timestamp)
{
    return EPOCH.AddSeconds(timestamp);
}

public static long ToUnixTimestamp(DateTime date)
{
    TimeSpan diff = date.ToUniversalTime() - EPOCH;
    return (long)diff.TotalSeconds;
}

public static DateTime FromIso8601FormattedDateTime(string iso8601DateTime){
    return DateTime.ParseExact(iso8601DateTime,"o", System.Globalization.CultureInfo.InvariantCulture);
}

public static string ToIso8601FormattedDateTime(DateTime dateTime)
{
    return dateTime.ToString("o");
}

在CodePlex项目中可以随意使用。


通配符字符串比较:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public static bool MatchesWildcard(this string text, string pattern)
{
    int it = 0;
    while (text.CharAt(it) != 0 &&
           pattern.CharAt(it) != '*')
    {
        if (pattern.CharAt(it) != text.CharAt(it) && pattern.CharAt(it) != '?')
            return false;
        it++;
    }

    int cp = 0;
    int mp = 0;
    int ip = it;

    while (text.CharAt(it) != 0)
    {
        if (pattern.CharAt(ip) == '*')
        {
            if (pattern.CharAt(++ip) == 0)
                return true;
            mp = ip;
            cp = it + 1;
        }
        else if (pattern.CharAt(ip) == text.CharAt(it) || pattern.CharAt(ip) == '?')
        {
            ip++;
            it++;
        }
        else
        {
            ip = mp;
            it = cp++;
        }
    }

    while (pattern.CharAt(ip) == '*')
    {
        ip++;
    }
    return pattern.CharAt(ip) == 0;
}

public static char CharAt(this string s, int index)
{
    if (index < s.Length)
        return s[index];
    return '\0';
}

这是本文中C代码的直接翻译,因此,CharAt方法返回0作为字符串结尾。

1
2
3
4
if (fileName.MatchesWildcard("*.cs"))
{
    Console.WriteLine("{0} is a C# source file", fileName);
}


这是我经常使用的唯一扩展名。它使使用system.net.mail发送电子邮件变得更加容易。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static class MailExtension
{
    // GetEmailCreditial(out strServer) gets credentials from an XML file
    public static void Send(this MailMessage email)
    {
        string strServer = String.Empty;
        NetworkCredential credentials = GetEmailCreditial(out strServer);
        SmtpClient client = new SmtpClient(strServer) { Credentials = credentials };
        client.Send(email);
    }

    public static void Send(this IEnumerable<MailMessage> emails)
    {
        string strServer = String.Empty;
        NetworkCredential credentials = GetEmailCreditial(out strServer);
        SmtpClient client = new SmtpClient(strServer) { Credentials = credentials };
        foreach (MailMessage email in emails)
            client.Send(email);
    }
}

// Example of use:
new MailMessage("[email protected]","[email protected]","This is an important Subject","Body goes here").Send();
//Assume email1,email2,email3 are MailMessage objects
new List<MailMessage>(){email1, email2, email}.Send();

在与MVC合作时,我有很多if声明,我只关心truefalse,打印nullstring.Empty,在另一种情况下,我想出了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static TResult WhenTrue<TResult>(this Boolean value, Func<TResult> expression)
{
    return value ? expression() : default(TResult);
}

public static TResult WhenTrue<TResult>(this Boolean value, TResult content)
{
    return value ? content : default(TResult);
}

public static TResult WhenFalse<TResult>(this Boolean value, Func<TResult> expression)
{
    return !value ? expression() : default(TResult);
}

public static TResult WhenFalse<TResult>(this Boolean value, TResult content)
{
    return !value ? content : default(TResult);
}

它允许我把<%= (someBool) ?"print y" : string.Empty %>改成<%= someBool.WhenTrue("print y") %>

我只在我混合代码和HTML的视图中使用它,在代码文件中编写"更长"的版本更清晰。


http://www.codeplex.com/linqext/


我想我以前在某个地方见过这个,但在这里找不到它的建议。MS在IDictionary接口上有一个TryGetValue函数,但它返回一个bool并给出out参数中的值,因此这里有一个更简单、更清晰的实现:

1
2
3
4
5
public static TVal GetValueOrDefault<TKey, TVal>(this IDictionary<TKey, TVal> d, TKey key) {
  if (d.ContainsKey(key))
    return d[key];
  return default(TVal);
}


用于单元测试:

1
2
3
4
5
6
7
8
9
public static IList<T> Clone<T>(this IList<T> list) where T : ICloneable
{
    var ret = new List<T>(list.Count);
    foreach (var item in list)
        ret.Add((T)item.Clone());

    // done
    return ret;
}

一系列类似twith2sugars的缩写语法:

1
2
3
4
5
public static long? ToNullableInt64(this string val)
{
    long ret;
    return Int64.TryParse(val, out ret) ? ret : new long?();
}

最后一点,BCL中是否已经有了这样的功能?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static void Split<T>(this T[] array,
    Func<T,bool> determinator,
    IList<T> onTrue,
    IList<T> onFalse)
{
    if (onTrue == null)
        onTrue = new List<T>();
    else
        onTrue.Clear();

    if (onFalse == null)
        onFalse = new List<T>();
    else
        onFalse.Clear();

    if (determinator == null)
        return;

    foreach (var item in array)
    {
        if (determinator(item))
            onTrue.Add(item);
        else
            onFalse.Add(item);
    }
}


我喜欢这些方法来处理具有flags属性集的枚举:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static bool AnyOf(this object mask, object flags)
{
    return ((int)mask & (int)flags) != 0;
}
public static bool AllOf(this object mask, object flags)
{
    return ((int)mask & (int)flags) == (int)flags;
}
public static object SetOn(this object mask, object flags)
{
    return (int)mask | (int)flags;
}
etc.

示例用法:

1
2
3
4
5
6
7
var options = SomeOptions.OptionA;
options = options.SetOn(OptionB);
options = options.SetOn(OptionC);

if (options.AnyOf(SomeOptions.OptionA | SomeOptions.OptionB))
{
etc.

最初的方法来自本文:http://www.codeproject.com/kb/cs/masksandflags.aspx?显示=打印我刚把它们转换成扩展方法。

不过,它们的一个问题是对象类型的参数,这意味着所有对象最终都将使用这些方法进行扩展,而理想情况下,它们只应用于枚举。

更新根据评论,你可以绕过"签名污染",以牺牲性能为代价,比如:

1
2
3
4
public static bool AnyOf(this Enum mask, object flags)
{
    return (Convert.ToInt642(mask) & (int)flags) != 0;
}


我写得像四千亿个扩展方法,所以这里有一些我觉得特别有用的方法。请随意执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
public static class ControlExtenders
{
    /// <summary>
    /// Advanced version of find control.
    /// </summary>
    /// <typeparam name="T">Type of control to find.</typeparam>
    /// <param name="id">Control id to find.</param>
    /// <returns>Control of given type.</returns>
    /// <remarks>
    /// If the control with the given id is not found
    /// a new control instance of the given type is returned.
    /// </remarks>
    public static T FindControl<T>(this Control control, string id) where T : Control
    {
        // User normal FindControl method to get the control
        Control _control = control.FindControl(id);

        // If control was found and is of the correct type we return it
        if (_control != null && _control is T)
        {
            // Return new control
            return (T)_control;
        }

        // Create new control instance
        _control = (T)Activator.CreateInstance(typeof(T));

        // Add control to source control so the
        // next it is found and the value can be
        // passed on itd, remember to hide it and
        // set an ID so it can be found next time
        if (!(_control is ExtenderControlBase))
        {
            _control.Visible = false;
        }
        _control.ID = id;
        control.Controls.Add(_control);

        // Use reflection to create a new instance of the control
        return (T)_control;
    }
}

public static class GenericListExtenders
{
    /// <summary>
    /// Sorts a generic list by items properties.
    /// </summary>
    /// <typeparam name="T">Type of collection.</typeparam>
    /// <param name="list">Generic list.</param>
    /// <param name="fieldName">Field to sort data on.</param>
    /// <param name="sortDirection">Sort direction.</param>
    /// <remarks>
    /// Use this method when a dinamyc sort field is requiered. If the
    /// sorting field is known manual sorting might improve performance.
    /// </remarks>
    public static void SortObjects<T>(this List<T> list, string fieldName, SortDirection sortDirection)
    {
        PropertyInfo propInfo = typeof(T).GetProperty(fieldName);
        if (propInfo != null)
        {
            Comparison<T> compare = delegate(T a, T b)
            {
                bool asc = sortDirection == SortDirection.Ascending;
                object valueA = asc ? propInfo.GetValue(a, null) : propInfo.GetValue(b, null);
                object valueB = asc ? propInfo.GetValue(b, null) : propInfo.GetValue(a, null);
                return valueA is IComparable ? ((IComparable)valueA).CompareTo(valueB) : 0;
            };
            list.Sort(compare);
        }
    }

    /// <summary>
    /// Creates a pagged collection from generic list.
    /// </summary>
    /// <typeparam name="T">Type of collection.</typeparam>
    /// <param name="list">Generic list.</param>
    /// <param name="sortField">Field to sort data on.</param>
    /// <param name="sortDirection">Sort direction.</param>
    /// <param name="from">Page from item index.</param>
    /// <param name="to">Page to item index.</param>
    /// <param name="copy">Creates a copy and returns a new list instead of changing the current one.</param>
    /// <returns>Pagged list collection.</returns>
    public static List<T> Page<T>(this List<T> list, string sortField, bool sortDirection, int from, int to, bool copy)
    {
        List<T> _pageList = new List<T>();

        // Copy list
        if (copy)
        {
            T[] _arrList = new T[list.Count];
            list.CopyTo(_arrList);
            _pageList = new List<T>(_arrList);
        }
        else
        {
            _pageList = list;
        }

        // Make sure there are enough items in the list
        if (from > _pageList.Count)
        {
            int diff = Math.Abs(from - to);
            from = _pageList.Count - diff;
        }
        if (to > _pageList.Count)
        {
            to = _pageList.Count;
        }

        // Sort items
        if (!string.IsNullOrEmpty(sortField))
        {
            SortDirection sortDir = SortDirection.Descending;
            if (!sortDirection) sortDir = SortDirection.Ascending;
            _pageList.SortObjects(sortField, sortDir);
        }

        // Calculate max number of items per page
        int count = to - from;
        if (from + count > _pageList.Count) count -= (from + count) - _pageList.Count;

        // Get max number of items per page
        T[] pagged = new T[count];
        _pageList.CopyTo(from, pagged, 0, count);

        // Return pagged items
        return new List<T>(pagged);
    }

    /// <summary>
    /// Shuffle's list items.
    /// </summary>
    /// <typeparam name="T">List type.</typeparam>
    /// <param name="list">Generic list.</param>
    public static void Shuffle<T>(this List<T> list)
    {
        Random rng = new Random();
        for (int i = list.Count - 1; i > 0; i--)
        {
            int swapIndex = rng.Next(i + 1);
            if (swapIndex != i)
            {
                T tmp = list[swapIndex];
                list[swapIndex] = list[i];
                list[i] = tmp;
            }
        }
    }

    /// <summary>
    /// Converts generic List to DataTable.
    /// </summary>
    /// <typeparam name="T">Type.</typeparam>
    /// <param name="list">Generic list.</param>
    /// <param name="columns">Name of the columns to copy to the DataTable.</param>
    /// <returns>DataTable.</returns>
    public static DataTable ToDataTable<T>(this List<T> list, string[] columns)
    {
        List<string> _columns = new List<string>(columns);
        DataTable dt = new DataTable();

        foreach (PropertyInfo info in typeof(T).GetProperties())
        {
            if (_columns.Contains(info.Name) || columns == null)
            {
                dt.Columns.Add(new DataColumn(info.Name, info.PropertyType));
            }
        }
        foreach (T t in list)
        {
            DataRow row = dt.NewRow();
            foreach (PropertyInfo info in typeof(T).GetProperties())
            {
                if (_columns.Contains(info.Name) || columns == null)
                {
                    row[info.Name] = info.GetValue(t, null);
                }
            }
            dt.Rows.Add(row);
        }
        return dt;
    }
}

public static class DateTimeExtenders
{
    /// <summary>
    /// Returns number of month from a string representation.
    /// </summary>
    /// <returns>Number of month.</returns>
    public static int MonthToNumber(this DateTime datetime, string month)
    {
        month = month.ToLower();
        for (int i = 1; i <= 12; i++)
        {
            DateTime _dt = DateTime.Parse("1." + i +".2000");
            string _month = CultureInfo.InvariantCulture.DateTimeFormat.GetMonthName(i).ToLower();
            if (_month == month)
            {
                return i;
            }
        }
        return 0;
    }

    /// <summary>
    /// Returns month name from month number.
    /// </summary>
    /// <returns>Name of month.</returns>
    public static string MonthToName(this DateTime datetime, int month)
    {
        for (int i = 1; i <= 12; i++)
        {
            if (i == month)
            {
                return CultureInfo.InvariantCulture.DateTimeFormat.GetMonthName(i);
            }
        }
        return"";
    }
}

public static class ObjectExtender
{
    public static object CloneBinary<T>(this T originalObject)
    {
        using (var stream = new System.IO.MemoryStream())
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            binaryFormatter.Serialize(stream, originalObject);
            stream.Position = 0;
            return (T)binaryFormatter.Deserialize(stream);
        }
    }

    public static object CloneObject(this object obj)
    {
        using (MemoryStream memStream = new MemoryStream())
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
            binaryFormatter.Serialize(memStream, obj);
            memStream.Position = 0;
            return binaryFormatter.Deserialize(memStream);
        }
    }
}

public static class StringExtenders
{
    /// <summary>
    /// Returns string as unit.
    /// </summary>
    /// <param name="value">Value.</param>
    /// <returns>Unit</returns>
    public static Unit ToUnit(this string value)
    {
        // Return empty unit
        if (string.IsNullOrEmpty(value))
            return Unit.Empty;

        // Trim value
        value = value.Trim();

        // Return pixel unit
        if (value.EndsWith("px"))
        {
            // Set unit type
            string _int = value.Replace("px","");

            // Try parsing to int
            double _val = 0;
            if (!double.TryParse(_int, out _val))
            {
                // Invalid value
                return Unit.Empty;
            }

            // Return unit
            return new Unit(_val, UnitType.Pixel);
        }

        // Return percent unit
        if (value.EndsWith("%"))
        {
            // Set unit type
            string _int = value.Replace("%","");

            // Try parsing to int
            double _val = 0;
            if (!double.TryParse(_int, out _val))
            {
                // Invalid value
                return Unit.Empty;
            }

            // Return unit
            return new Unit(_val, UnitType.Percentage);
        }

        // No match found
        return new Unit();
    }

    /// <summary>
    /// Returns alternative string if current string is null or empty.
    /// </summary>
    /// <param name="str"></param>
    /// <param name="alternative"></param>
    /// <returns></returns>
    public static string Alternative(this string str, string alternative)
    {
        if (string.IsNullOrEmpty(str)) return alternative;
        return str;
    }

    /// <summary>
    /// Removes all HTML tags from string.
    /// </summary>
    /// <param name="html">String containing HTML tags.</param>
    /// <returns>String with no HTML tags.</returns>
    public static string StripHTML(this string html)
    {
        string nohtml = Regex.Replace(html,"<(.|
)*?>"
,"");
        nohtml = nohtml.Replace("

"
,"").Replace("
"
,"").Replace("&nbsp;","").Trim();
        return nohtml;
    }
}

第一个是我最喜欢的,因为它可以让我替换:

1
2
3
4
5
6
Control c = this.FindControl("tbName");
if (c != null)
{
    // Do something with c
    customer.Name = ((TextBox)c).Text;
}

用这个:

1
2
TextBox c = this.FindControl<TextBox>("tbName");
customer.Name = c.Text;

设置默认字符串值:

1
2
3
4
5
string str ="";
if (string.IsNullOrEmpty(str))
{
    str ="I'm empty!";
}

变成:

1
str = str.Alternative("I'm empty!");

在将表单输入放入数据库之前解析表单输入时,这些扩展方法对我非常有用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static int? ToInt(this string input)
{
    int val;
    if (int.TryParse(input, out val))
        return val;
    return null;
}

public static DateTime? ToDate(this string input)
{
    DateTime val;
    if (DateTime.TryParse(input, out val))
        return val;
    return null;
}

public static decimal? ToDecimal(this string input)
{
    decimal val;
    if (decimal.TryParse(input, out val))
        return val;
    return null;
}

每N个字符包装一个字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static string WrapAt(this string str, int WrapPos)
{
    if (string.IsNullOrEmpty(str))
        throw new ArgumentNullException("str","Cannot wrap a null string");
    str = str.Replace("
"
,"").Replace("
"
,"");

    if (str.Length <= WrapPos)
        return str;

    for (int i = str.Length; i >= 0; i--)
        if (i % WrapPos == 0 && i > 0 && i != str.Length)
            str = str.Insert(i,"

"
);
    return str;
}

这是另一个我一直在使用的控件扩展,尽管我不知道它以前是否发布在这里。

1
2
3
4
5
6
7
8
9
10
11
12
public static class ControlExtensions
{
    public static void DoubleBuffer(this Control control)
    {
        // http://stackoverflow.com/questions/76993/how-to-double-buffer-net-controls-on-a-form/77233#77233
        // Taxes: Remote Desktop Connection and painting: http://blogs.msdn.com/oldnewthing/archive/2006/01/03/508694.aspx

        if (System.Windows.Forms.SystemInformation.TerminalServerSession) return;
        System.Reflection.PropertyInfo dbProp = typeof(System.Windows.Forms.Control).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        dbProp.SetValue(control, true, null);
    }
}

用途:

1
this.someControl.DoubleBuffer();

get member name允许获取具有编译时安全性的成员名称的字符串。

1
2
3
4
5
6
public static string GetMemberName<T, TResult>(
    this T anyObject,
    Expression<Func<T, TResult>> expression)
{
    return ((MemberExpression)expression.Body).Member.Name;
}

用途:

1
"blah".GetMemberName(x => x.Length); // returns"Length"

如果没有实例,它将与非扩展静态方法一起提供:

1
2
3
4
5
6
public static string GetMemberName<T, TReturn>(
    Expression<Func<T, TReturn>> expression)
    where T : class
{
    return ((MemberExpression)expression.Body).Member.Name;
}

但电话看起来不太漂亮,当然:

1
ReflectionUtility.GetMemberName((string) s => s.Length); // returns"Length"

如果你愿意,你可以把它放在codeplex上。


ASP MVC的空部分HTML帮助程序。

传递空模型时,html.partial和html.renderpartial将提供视图的模型,如果此部分是强类型的,并且视图的类型不同,则它将引发异常,而不是传递空引用。这些帮助器允许您指定两个不同的部分,这样您就可以将空测试保留在视图之外。

您有权在codeplex页面中包含此内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public static class nullpartials
    {
        public static MvcHtmlString NullPartial(this HtmlHelper helper, string Partial, string NullPartial, object Model)
        {
            if (Model == null)
                return helper.Partial(NullPartial);
            else
                return helper.Partial(Partial, Model);
        }

        public static MvcHtmlString NullPartial(this HtmlHelper helper, string Partial, string NullPartial, object Model, ViewDataDictionary viewdata)
        {
            if (Model == null)
                return helper.Partial(NullPartial, viewdata);
            else
                return helper.Partial(Partial, Model, viewdata);
        }

        public static void RenderNullPartial(this HtmlHelper helper, string Partial, string NullPartial, object Model)
        {
            if (Model == null)
            {
                helper.RenderPartial(NullPartial);
                return;
            }
            else
            {
                helper.RenderPartial(Partial, Model);
                return;
            }
        }

        public static void RenderNullPartial(this HtmlHelper helper, string Partial, string NullPartial, object Model, ViewDataDictionary viewdata)
        {
            if (Model == null)
            {
                helper.RenderPartial(NullPartial, viewdata);
                return;
            }
            else
            {
                helper.RenderPartial(Partial, Model, viewdata);
                return;
            }
        }
    }


我一直在寻找一种方法来为社区贡献我所开发的一些东西。

这里有一些文件信息扩展,我觉得非常有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/// <summary>
/// Open with default 'open' program
/// </summary>
/// <param name="value"></param>
public static Process Open(this FileInfo value)
{
    if (!value.Exists)
        throw new FileNotFoundException("File doesn't exist");
    Process p = new Process();
    p.StartInfo.FileName = value.FullName;
    p.StartInfo.Verb ="Open";
    p.Start();
    return p;
}

/// <summary>
/// Print the file
/// </summary>
/// <param name="value"></param>
public static void Print(this FileInfo value)
{
    if (!value.Exists)
        throw new FileNotFoundException("File doesn't exist");
    Process p = new Process();
    p.StartInfo.FileName = value.FullName;
    p.StartInfo.Verb ="Print";
    p.Start();
}

/// <summary>
/// Send this file to the Recycle Bin
/// </summary>
/// <exception cref="File doesn't exist" />
/// <param name="value"></param>
public static void Recycle(this FileInfo value)
{        
    value.Recycle(false);
}

/// <summary>
/// Send this file to the Recycle Bin
/// On show, if person refuses to send file to the recycle bin,
/// exception is thrown or otherwise delete fails
/// </summary>
/// <exception cref="File doesn't exist" />
/// <exception cref="On show, if user refuses, throws exception 'The operation was canceled.'" />
/// <param name="value">File being recycled</param>
/// <param name="showDialog">true to show pop-up</param>
public static void Recycle(this FileInfo value, bool showDialog)
{
    if (!value.Exists)
            throw new FileNotFoundException("File doesn't exist");
    if( showDialog )
        FileSystem.DeleteFile
            (value.FullName, UIOption.AllDialogs,
            RecycleOption.SendToRecycleBin);
    else
        FileSystem.DeleteFile
            (value.FullName, UIOption.OnlyErrorDialogs,
            RecycleOption.SendToRecycleBin);
}

在用户最喜爱的编辑器中打开任何文件:

1
new FileInfo("C:\image.jpg").Open();

打印操作系统知道如何打印的任何文件:

1
new FileInfo("C:\image.jpg").Print();

将任何文件发送到回收站:

  • 你必须包括Microsoft.VisualBasic号文件
  • 使用using Microsoft.VisualBasic.FileIO;
  • 例子:

    1
    new FileInfo("C:\image.jpg").Recycle();

    1
    2
    // let user have a chance to cancel send to recycle bin.
    new FileInfo("C:\image.jpg").Recycle(true);


    从集合中加载默认设置的一种更简单的方法(在现实生活中,我使用它来填充来自任何源的设置,包括命令行、ClickOnce URL参数等):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public static void LoadFrom(this ApplicationSettingsBase settings, NameValueCollection configuration)
    {
        if (configuration != null)
            foreach (string key in configuration.AllKeys)
                if (!String.IsNullOrEmpty(key))
                    try
                    {
                        settings[key] = configuration.Get(key);
                    }
                    catch (SettingsPropertyNotFoundException)
                    {
                      // handle bad arguments as you wish
                    }
    }

    例子:

    1
    Settings.Default.LoadFrom(new NameValueCollection() { {"Setting1","Value1" }, {"Setting2","Value2" } });


    这个非常有用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
        public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> selector)
        {
            if (first == null)
                throw new ArgumentNullException("first");
            if (second == null)
                throw new ArgumentNullException("second");
            if (selector == null)
                throw new ArgumentNullException("selector");

            using (var enum1 = first.GetEnumerator())
            using (var enum2 = second.GetEnumerator())
            {
                while (enum1.MoveNext() && enum2.MoveNext())
                {
                    yield return selector(enum1.Current, enum2.Current);
                }
            }
        }

    它已经添加到.NET 4.0中的Enumerable类中,但是在3.5中使用它很方便。

    例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var names = new[] {"Joe","Jane","Jack","John" };
    var ages = new[] { 42, 22, 18, 33 };

    var persons = names.Zip(ages, (n, a) => new { Name = n, Age = a });

    foreach (var p in persons)
    {
        Console.WriteLine("{0} is {1} years old", p.Name, p.Age);
    }


    下面是一些方法,我使用这些方法来减少提取单个属性的痛苦:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public static T GetAttribute<T>(this ICustomAttributeProvider provider, bool inherit = false, int index = 0) where T : Attribute
    {
        return provider.GetAttribute(typeof(T), inherit, index) as T;
    }

    public static Attribute GetAttribute(this ICustomAttributeProvider provider, Type type, bool inherit = false, int index = 0)
    {
        bool exists = provider.IsDefined(type, inherit);
        if (!exists)
        {
            return null;
        }

        object[] attributes = provider.GetCustomAttributes(type, inherit);
        if (attributes != null && attributes.Length != 0)
        {
            return attributes[index] as Attribute;
        }
        else
        {
            return null;
        }
    }

    用法(此枚举描述hack的实现):

    1
    2
    3
    4
    5
    6
    public static string GetDescription(this Enum value)
    {
        var fieldInfo = value.GetType().GetField(value.ToString());
        var attribute = fieldInfo.GetAttribute<DescriptionAttribute>();
        return attribute != null ? attribute.Description : null;
    }

    请随意将其包含在codeplex项目中!


    在.NET中,有一个IndexOf和一个LastIndexOf方法返回String对象中匹配的第一次和最后一次出现的索引。我有一个扩展方法来获取第n个事件的索引:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public static partial class StringExtensions {

        public static int NthIndexOf(this String str, String match, int occurrence) {
            int i = 1;
            int index = 0;

            while (i <= occurrence &&
                ( index = str.IndexOf(match, index + 1) ) != -1) {

                if (i == occurrence) {
                    // Occurrence match found!
                    return index;
                }
                i++;
            }

            // Match not found
            return -1;
        }
    }

    我经常用这个…

    原代码:

    1
    2
    if (guid != Guid.Empty) return guid;
    else return Guid.NewGuid();

    新代码:

    1
    return guid.NewGuidIfEmpty();

    扩展方法:

    1
    2
    3
    4
    public static Guid NewGuidIfEmpty(this Guid uuid)
    {
        return (uuid != Guid.Empty ? uuid : Guid.NewGuid());
    }


    我把两个小的(有些人觉得他们很傻)放在我所有的项目中是:

    1
    2
    3
    public static bool IsNull(this object o){
      return o == null;
    }

    1
    2
    3
    public static bool IsNullOrEmpty(this string s){
      return string.IsNullOrEmpty(s);
    }

    它使我的代码更加流畅……

    1
    2
    3
    if (myClassInstance.IsNull()) //... do something

    if (myString.IsNullOrEmpty()) //... do something

    我认为,如果我们得到这些属性,它们将成为非常好的扩展属性。


    将字符串的长度减小到toLength,并在缩短后的字符串末尾添加一个额外的字符串,以表示字符串已缩短(默认为...)

    1
    2
    3
    4
    5
    6
    7
    public static string Shorten(this string str, int toLength, string cutOffReplacement =" ...")
    {
        if (string.IsNullOrEmpty(str) || str.Length <= toLength)
            return str;
        else
            return str.Remove(toLength) + cutOffReplacement;
    }


    我确信这是以前做过的,但我发现自己经常使用这种方法(和更简单的导数):

    1
    2
    3
    4
    public static bool CompareEx(this string strA, string strB, CultureInfo culture, bool ignoreCase)
    {
        return string.Compare(strA, strB, ignoreCase, culture) == 0;
    }

    您可以用多种方式编写它,但我喜欢它,因为它很快统一了我在保存代码行(或代码字符)的同时比较字符串的方法。


    带内置铸件的findcontrol:

    1
    2
    3
    4
    public static T FindControl<T>(this Control control, string id) where T : Control
    {
        return (T)control.FindControl(id);
    }

    这没什么了不起的,但我觉得它有助于实现更清晰的代码。

    1
    2
    3
    4
    5
    // With extension method
    container.FindControl<TextBox>("myTextBox").SelectedValue ="Hello world!";

    // Without extension method
    ((TextBox)container.FindControl("myTextBox")).SelectedValue ="Hello world!";

    如果需要的话,可以将其放到codeplex项目中。


    我最常用的扩展名是可以格式化字节数组的扩展名:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    /// <summary>
    /// Returns a string representation of a byte array.
    /// </summary>
    /// <param name="bytearray">The byte array to represent.</param>
    /// <param name="subdivision">The number of elements per group,
    /// or 0 to not restrict it. The default is 0.</param>
    /// <param name="subsubdivision">The number of elements per line,
    /// or 0 to not restrict it. The default is 0.</param>
    /// <param name="divider">The string dividing the individual bytes. The default is"".</param>
    /// <param name="subdivider">The string dividing the groups. The default is" ".</param>
    /// <param name="subsubdivider">The string dividing the lines. The default is"

    ".</param>
    /// <param name="
    uppercase">Whether the representation is in uppercase hexadecimal.
    /// The default is <see langword="
    true"/>.</param>
    /// <param name="
    prebyte">The string to put before each byte. The default is an empty string.</param>
    /// <param name="
    postbyte">The string to put after each byte. The default is an empty string.</param>
    /// <returns>The string representation.</returns>
    /// <exception cref="
    ArgumentNullException">
    /// <paramref name="
    bytearray"/> is <see langword="null"/>.
    /// </exception>
    public static string ToArrayString(this byte[] bytearray,
        int subdivision = 0,
        int subsubdivision = 0,
        string divider ="
    ",
        string subdivider ="
    ",
        string subsubdivider ="


    ",
        bool uppercase = true,
        string prebyte ="
    ",
        string postbyte ="
    ")
    {
        #region Contract
        if (bytearray == null)
            throw new ArgumentNullException("
    bytearray");
        #endregion

        StringBuilder sb = new StringBuilder(
            bytearray.Length * (2 + divider.Length + prebyte.Length + postbyte.Length) +
            (subdivision > 0 ? (bytearray.Length / subdivision) * subdivider.Length : 0) +
            (subsubdivision > 0 ? (bytearray.Length / subsubdivision) * subsubdivider.Length : 0));
        int groupElements = (subdivision > 0 ? subdivision - 1 : -1);
        int lineElements = (subsubdivision > 0 ? subsubdivision - 1 : -1);
        for (long i = 0; i < bytearray.LongLength - 1; i++)
        {
            sb.Append(prebyte);
            sb.Append(String.Format(CultureInfo.InvariantCulture, (uppercase ?"
    {0:X2}" :"{0:x2}"), bytearray[i]));
            sb.Append(postbyte);

            if (lineElements == 0)
            {
                sb.Append(subsubdivider);
                groupElements = subdivision;
                lineElements = subsubdivision;
            }
            else if (groupElements == 0)
            {
                sb.Append(subdivider);
                groupElements = subdivision;
            }
            else
                sb.Append(divider);

            lineElements--;
            groupElements--;
        }
        sb.Append(prebyte);
        sb.Append(String.Format(CultureInfo.InvariantCulture, (uppercase ?"
    {0:X2}" :"{0:x2}"), bytearray[bytearray.LongLength - 1]));
        sb.Append(postbyte);

        return sb.ToString();
    }

    默认情况下,ToArrayString()只将字节数组打印为单个字节的长字符串。但是,ToArrayString(4, 16)将字节分组为四个字节组,一行16个字节,就像您最喜欢的十六进制编辑器中那样。下面很好地格式化了字节数组,以便在C代码中使用:

    1
    2
    3
    4
    byte[] bytearray = new byte[]{ ... };
    Console.Write(bytearray.ToArrayString(4, 16,",",",  ",",

    "
    , true,"0x"));

    它是我写的,所以你可以把它放到密码丛上。


    灵感来源于弦乐。

    验证给定列表是否为空

    1
    2
    3
    4
    public static bool IsNullOrEmpty<TSource>(this List<TSource> src)
    {            
        return (src == null || src.Count == 0);
    }

    这个是为了验证给定的2个文件和属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public static bool Compare(this FileInfo f1, FileInfo f2, string propertyName)
    {
        try
        {
            PropertyInfo p1 = f1.GetType().GetProperty(propertyName);
            PropertyInfo p2 = f2.GetType().GetProperty(propertyName);

            if (p1.GetValue(f1, null) == p2.GetValue(f1, null))
                return true;
        }
        catch (Exception ex)
        {
            return false;
        }
        return false;
    }

    像这样使用

    1
    2
    3
    4
    5
    6
    FileInfo fo = new FileInfo("c:\
    etlog.txt"
    );
    FileInfo f1 = new FileInfo("c:\
    egkey.txt"
    );

    fo.compare(f1,"CreationTime");


    在WinForms中用于填充组合框:

    1
    2
    3
    4
    5
    List<MyObject> myObjects = new List<MyObject>() {
        new MyObject() {Name ="a", Id = 0},
        new MyObject() {Name ="b", Id = 1},
        new MyObject() {Name ="c", Id = 2} }
    comboBox.FillDataSource<MyObject>(myObjects, x => x.Name);

    扩展方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    /** <summary>Fills the System.Windows.Forms.ComboBox object DataSource with a
     * list of T objects.</summary>
     * <param name="values">The list of T objects.</param>
     * <param name="displayedValue">A function to apply to each element to get the
     * display value.</param>
     */

    public static void FillDataSource<T>(this ComboBox comboBox, List<T> values,
        Func<T, String> displayedValue) {

        // Create dataTable
        DataTable data = new DataTable();
        data.Columns.Add("ValueMember", typeof(T));
        data.Columns.Add("DisplayMember");

        for (int i = 0; i < values.Count; i++) {
            // For each value/displayed value

            // Create new row with value & displayed value
            DataRow dr = data.NewRow();
            dr["ValueMember"] = values[i];
            dr["DisplayMember"] = displayedValue(values[i]) ??"";
            // Add row to the dataTable
            data.Rows.Add(dr);
        }

        // Bind datasource to the comboBox
        comboBox.DataSource = data;
        comboBox.ValueMember ="ValueMember";
        comboBox.DisplayMember ="DisplayMember";
    }

    简洁地提出事件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public static void Raise(this EventHandler handler, object sender, EventArgs e)
    {
        if (handler != null)
        {
            handler(sender, e);
        }
    }

    public static void Raise<T>(this EventHandler<T> handler, object sender, T e) where T : EventArgs
    {
        if (handler != null)
        {
            handler(sender, e);
        }
    }

    用途:

    1
    2
    3
    4
    5
    6
    public event EventHandler Bar;

    public void Foo()
    {
        Bar.Raise(this, EventArgs.Empty);
    }

    这里有一些关于潜在线程安全问题的讨论。由于.NET4,上述表单是线程安全的,但如果使用旧版本,则需要重新排列和一些锁。


    我已经实现了一个扩展方法包(可在http://foop.codeplex.com/上找到),我日常使用的一些方法包括:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    // the most beloved extension method for me is Pipe:
    <%= variable.Pipe(x => this.SomeFunction(x)).Pipe(y =>
    {
        ...;
        return this.SomeOtherFunction(y);
    }) %>

    var d = 28.December(2009); // some extension methods for creating DateTime
    DateTime justDatePart = d.JustDate();
    TimeSpan justTimePart = d.JustTime();
    var nextTime = d.Add(5.Hours());

    using(StreamReader reader = new StreamReader("lines-of-data-file-for-example")) {
        ...
        // for reading streams line by line and usable in LINQ
        var query = from line in reader.Lines();
                    where line.Contains(_today)
                    select new { Parts = PartsOf(line), Time = _now };
    }

    500.Sleep();

    XmlSerialize and XmlDeserialize

    IsNull and IsNotNull

    IfTrue, IfFalse and Iff:
    true.IfTrue(() => Console.WriteLine("it is true then!");

    IfNull and IfNotNull


    这是ASP.NET MVC操作链接帮助器方法的扩展方法,允许它使用控制器的authorize属性来决定是否应在当前用户的视图中启用、禁用或隐藏链接。我不必将您的受限操作包含在检查所有视图中用户成员身份的"if"子句中。感谢Maarten Balliauw的想法和向我展示方法的代码位:)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Security.Principal;
    using System.Web.Routing;
    using System.Web.Mvc;
    using System.Collections;
    using System.Reflection;
    namespace System.Web.Mvc.Html
    {
        public static class HtmlHelperExtensions
        {

            /// <summary>
            /// Shows or hides an action link based on the user's membership status
            /// and the controller's authorize attributes
            /// </summary>
            /// <param name="linkText">The link text.</param>
            /// <param name="action">The controller action name.</param>
            /// <param name="controller">The controller name.</param>
            /// <returns></returns>
            public static string SecurityTrimmedActionLink(
                this HtmlHelper htmlHelper,
                string linkText,
                string action,
                string controller)
            {
                return SecurityTrimmedActionLink(htmlHelper, linkText, action, controller, false, null);
            }

            /// <summary>
            /// Enables, disables or hides an action link based on the user's membership status
            /// and the controller's authorize attributes
            /// </summary>
            /// <param name="linkText">The link text.</param>
            /// <param name="action">The action name.</param>
            /// <param name="controller">The controller name.</param>
            /// <param name="showDisabled">if set to <c>true</c> [show link as disabled -
            /// using a span tag instead of an anchor tag ].</param>
            /// <param name="disabledAttributeText">Use this to add attributes to the disabled
            /// span tag.</param>
            /// <returns></returns>
            public static string SecurityTrimmedActionLink(
                this HtmlHelper htmlHelper,
                string linkText,
                string action,
                string controller,
                bool showDisabled,
                string disabledAttributeText)
            {
                if (IsAccessibleToUser(action, controller, HttpContext.Current ))
                {
                    return htmlHelper.ActionLink(linkText, action, controller);
                }
                else
                {
                    return showDisabled ?
                        String.Format(
                           "<span{1}>{0}</span>",
                            linkText,
                            disabledAttributeText==null?"":""+disabledAttributeText
                            ) :"";
                }
            }

            private static IController GetControllerInstance(string controllerName)
            {
                Assembly assembly = Assembly.GetExecutingAssembly();
                Type controllerType = GetControllerType(controllerName);
                return (IController)Activator.CreateInstance(controllerType);
            }

            private static ArrayList GetControllerAttributes(string controllerName, HttpContext context)
            {
                if (context.Cache[controllerName +"_ControllerAttributes"] == null)
                {
                    var controller = GetControllerInstance(controllerName);

                    context.Cache.Add(
                        controllerName +"_ControllerAttributes",
                        new ArrayList(controller.GetType().GetCustomAttributes(typeof(AuthorizeAttribute), true)),
                        null,
                        Caching.Cache.NoAbsoluteExpiration,
                        Caching.Cache.NoSlidingExpiration,
                        Caching.CacheItemPriority.Default,
                        null);

                }
                return (ArrayList)context.Cache[controllerName +"_ControllerAttributes"];

            }

            private static ArrayList GetMethodAttributes(string controllerName, string actionName, HttpContext context)
            {
                if (context.Cache[controllerName +"_" + actionName +"_ActionAttributes"] == null)
                {
                    ArrayList actionAttrs = new ArrayList();
                    var controller = GetControllerInstance(controllerName);
                    MethodInfo[] methods = controller.GetType().GetMethods();

                    foreach (MethodInfo method in methods)
                    {
                        object[] attributes = method.GetCustomAttributes(typeof(ActionNameAttribute), true);

                        if ((attributes.Length == 0 && method.Name == actionName)
                            ||
                            (attributes.Length > 0 && ((ActionNameAttribute)attributes[0]).Name == actionName))
                        {
                            actionAttrs.AddRange(method.GetCustomAttributes(typeof(AuthorizeAttribute), true));
                        }
                    }

                    context.Cache.Add(
                        controllerName +"_" + actionName +"_ActionAttributes",
                        actionAttrs,
                        null,
                        Caching.Cache.NoAbsoluteExpiration,
                        Caching.Cache.NoSlidingExpiration,
                        Caching.CacheItemPriority.Default,
                        null);

                }

                return (ArrayList)context.Cache[controllerName +"_" + actionName+"_ActionAttributes"];
            }

            public static bool IsAccessibleToUser(string actionToAuthorize, string controllerToAuthorize, HttpContext context)
            {
                IPrincipal principal = context.User;

                //cache the attribute list for both controller class and it's methods

                ArrayList controllerAttributes = GetControllerAttributes(controllerToAuthorize, context);

                ArrayList actionAttributes = GetMethodAttributes(controllerToAuthorize, actionToAuthorize, context);                        

                if (controllerAttributes.Count == 0 && actionAttributes.Count == 0)
                    return true;

                string roles ="";
                string users ="";
                if (controllerAttributes.Count > 0)
                {
                    AuthorizeAttribute attribute = controllerAttributes[0] as AuthorizeAttribute;
                    roles += attribute.Roles;
                    users += attribute.Users;
                }
                if (actionAttributes.Count > 0)
                {
                    AuthorizeAttribute attribute = actionAttributes[0] as AuthorizeAttribute;
                    roles += attribute.Roles;
                    users += attribute.Users;
                }

                if (string.IsNullOrEmpty(roles) && string.IsNullOrEmpty(users) && principal.Identity.IsAuthenticated)
                    return true;

                string[] roleArray = roles.Split(',');
                string[] usersArray = users.Split(',');
                foreach (string role in roleArray)
                {
                    if (role =="*" || principal.IsInRole(role))
                        return true;
                }
                foreach (string user in usersArray)
                {
                    if (user =="*" && (principal.Identity.Name == user))
                        return true;
                }
                return false;
            }

            private static Type GetControllerType(string controllerName)
            {
                Assembly assembly = Assembly.GetExecutingAssembly();
                foreach (Type type in assembly.GetTypes())
                {
                    if (
                        type.BaseType!=null
                        && type.BaseType.Name =="Controller"
                        && (type.Name.ToUpper() == (controllerName.ToUpper() +"Controller".ToUpper())))
                    {
                        return type;
                    }
                }
                return null;
            }

        }
    }

    我还没有看到这个答案…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public static string[] Split(this string value, string regexPattern)
    {
        return value.Split(regexPattern, RegexOptions.None);
    }

    public static string[] Split(this string value, string regexPattern,
        RegexOptions options)
    {
        return Regex.Split(value, regexPattern, options);
    }

    用途:

    1
    2
    var obj ="test1,test2,test3";
    string[] arrays = obj.Split(",");

    有些时候需要类的实例,不管它是否有效,但不能为空。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public static T Safe<T>(this T obj) where T : new()
    {
        if (obj == null)
        {
            obj = new T();
        }

        return obj;
    }

    用法如下:

    1
    2
    MyClass myClass = Provider.GetSomeResult();
    string temp = myClass.Safe().SomeValue;

    而不是:

    1
    2
    3
    4
    5
    6
    MyClass myClass = Provider.GetSomeResult();
    string temp ="some default value";
    if (myClass != null)
    {
            temp = myClass.SomeValue;
    }

    对不起,如果是口是心非,但我找不到。


    我一直用这个:

    1
    2
    3
    4
    5
    6
    public static void DelimitedAppend(this StringBuilder sb, string value, string delimiter)
    {
        if (sb.Length > 0)
            sb.Append(delimiter);
        sb.Append(value);
    }

    这只是确保在字符串为空时不插入分隔符。例如,要创建逗号分隔的单词列表,请执行以下操作:

    1
    2
    3
    4
    var farmAnimals = new[] { new { Species ="Dog", IsTasty = false }, new { Species ="Cat", IsTasty = false }, new { Species ="Chicken", IsTasty = true }, };
    var soupIngredients = new StringBuilder();
    foreach (var edible in farmAnimals.Where(farmAnimal => farmAnimal.IsTasty))
        soupIngredients.DelimitedAppend(edible.Species,",");


    使用反射查找台盼色方法并在字符串目标上调用它。可选参数指定转换失败时应返回的内容。大多数时候,我觉得这个方法很有用。我很清楚Convert.ChangeType选项,但我发现这个选项更有用,它的默认结果很方便,而且不方便。请注意,找到的方法保存在字典中,尽管我确实怀疑拳击最终会减慢速度。

    这个方法是我最喜欢的,因为它合法地使用了很多语言特性。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    private static readonly Dictionary<Type, MethodInfo> Parsers = new Dictionary<Type, MethodInfo>();

    public static T Parse<T>(this string value, T defaultValue = default(T))
    {
        if (string.IsNullOrEmpty(value)) return defaultValue;

        if (!Parsers.ContainsKey(typeof(T)))
            Parsers[typeof (T)] = typeof (T).GetMethods(BindingFlags.Public | BindingFlags.Static)
                .Where(mi => mi.Name =="TryParse")
                .Single(mi =>
                            {
                                var parameters = mi.GetParameters();
                                if (parameters.Length != 2) return false;
                                return parameters[0].ParameterType == typeof (string) &&
                                       parameters[1].ParameterType == typeof (T).MakeByRefType();
                            });

        var @params = new object[] {value, default(T)};
        return (bool) Parsers[typeof (T)].Invoke(null, @params) ?
            (T) @params[1] : defaultValue;
    }

    用途:

    1
    2
    3
    var hundredTwentyThree ="123".Parse(0);
    var badnumber ="test".Parse(-1);
    var date ="01/01/01".Parse<DateTime>();


    下面是另一个Throwifnull实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    [ThreadStatic]
    private static string lastMethodName = null;

    [ThreadStatic]
    private static int lastParamIndex = 0;

    [MethodImpl(MethodImplOptions.NoInlining)]
    public static void ThrowIfNull<T>(this T parameter)
    {
        var currentStackFrame = new StackFrame(1);
        var props = currentStackFrame.GetMethod().GetParameters();

        if (!String.IsNullOrEmpty(lastMethodName)) {
            if (currentStackFrame.GetMethod().Name != lastMethodName) {
                lastParamIndex = 0;
            } else if (lastParamIndex >= props.Length - 1) {
                lastParamIndex = 0;
            } else {
                lastParamIndex++;
            }
        } else {
            lastParamIndex = 0;
        }

        if (!typeof(T).IsValueType) {
            for (int i = lastParamIndex; i &lt; props.Length; i++) {
                if (props[i].ParameterType.IsValueType) {
                    lastParamIndex++;
                } else {
                    break;
                }
            }
        }

        if (parameter == null) {
            string paramName = props[lastParamIndex].Name;
            throw new ArgumentNullException(paramName);
        }

        lastMethodName = currentStackFrame.GetMethod().Name;
    }

    它的效率不如其他实现方式,但使用更为清洁:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public void Foo()
    {
        Bar(1, 2,"Hello","World"); //no exception
        Bar(1, 2,"Hello", null); //exception
        Bar(1, 2, null,"World"); //exception
    }

    public void Bar(int x, int y, string someString1, string someString2)
    {
        //will also work with comments removed
        //x.ThrowIfNull();
        //y.ThrowIfNull();
        someString1.ThrowIfNull();
        someString2.ThrowIfNull();

        //Do something incredibly useful here!
    }

    将参数更改为int?也会起作用。

    票据


    使用列表的一些扩展:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    /// <summary>
    /// Wrap an object in a list
    /// </summary>
    public static IList<T> WrapInList<T>(this T item)
    {
        List<T> result = new List<T>();
        result.Add(item);
        return result;
    }

    使用EG:

    1
    myList = someObject.InList();

    使包含来自一个或多个源的项的IEnumerable更像列表。对于高性能代码来说,这可能不是一个好主意,但对于进行测试很有用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public static IEnumerable<T> Append<T>(this IEnumerable<T> enumerable, T newItem)
    {
        foreach (T item in enumerable)
        {
            yield return item;
        }

        yield return newItem;
    }

    public static IEnumerable<T> Append<T>(this IEnumerable<T> enumerable, params T[] newItems)
    {
        foreach (T item in enumerable)
        {
            yield return item;
        }

        foreach (T newItem in newItems)
        {
            yield return newItem;
        }
    }

    使用例如

    1
    someEnumeration = someEnumeration.Append(newItem);

    其他可能的变化-例如

    1
    someEnumeration = someEnumeration.Append(otherEnumeration);

    如果要克隆项目,还可能需要克隆它们的列表:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public static IList<T> Clone<T>(this IEnumerable<T> source) where T: ICloneable
    {
        List<T> result = new List<T>();

        foreach (T item in source)
        {
            result.Add((T)item.Clone());
        }

        return result;
    }

    当我使用ObservableCollection时,通常使用addrange方法来扩展它。这里的其他答案给出了这个的实现。

    如果需要,可以将此代码放入codeplex项目中。


    讨厌这种代码?

    1
    2
    3
    4
    5
    6
    7
    8
    CloneableClass cc1 = new CloneableClass ();
    CloneableClass cc2 = null;
    CloneableClass cc3 = null;

    cc3 = (CloneableClass) cc1.Clone (); // this is ok
    cc3 = cc2.Clone (); // this throws null ref exception
    // code to handle both cases
    cc3 = cc1 != null ? (CloneableClass) cc1.Clone () : null;

    它有点笨重,所以我把它换成这个扩展,我称之为cloneornull-

    1
    2
    3
    4
    5
    public static T CloneOrNull<T> (this T self) where T : class, ICloneable
    {
        if (self == null) return null;
        return (T) self.Clone ();
    }

    用法如下:

    1
    2
    3
    4
    5
    6
    7
    CloneableClass cc1 = new CloneableClass ();
    CloneableClass cc2 = null;
    CloneableClass cc3 = null;

    cc3 = cc1.CloneOrNull (); // clone of cc1
    cc3 = cc2.CloneOrNull (); // null
    // look mom, no casts!

    请随意在任何地方使用!


    ASP.NET HTML编码-短而甜:

    1
    2
    3
    4
    5
    6
    public static string ToHtmlEncodedString(this string s)
    {
        if (String.IsNullOrEmpty(s))
            return s;
        return HttpUtility.HtmlEncode(s);
    }

    一些方便的字符串助手:

    用途:

    我讨厌不需要的空格尾随或前导字符串,而且由于字符串可以接受null值,所以很难处理,所以我使用这个:

    1
    public bool IsGroup { get { return !this.GroupName.IsNullOrTrimEmpty(); } }

    这里是另一个扩展方法,我将它用于我正在试验的新验证框架。您可以看到其中的regex扩展有助于清除其他混乱的regex:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public static bool IsRequiredWithLengthLessThanOrEqualNoSpecial(this String str, int length)
    {
        return !str.IsNullOrTrimEmpty() &&
            str.RegexMatch(
                @"^[-

    \\\.!:*,@$%&"
    "?\(\)\w']{1,{0}}$".RegexReplace(@"\{0\}", length.ToString()),
                RegexOptions.Multiline) == str;
    }

    来源:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    public static class StringHelpers
    {
        /// <summary>
        /// Same as String.IsNullOrEmpty except that
        /// it captures the Empty state for whitespace
        /// strings by Trimming first.
        /// </summary>
        public static bool IsNullOrTrimEmpty(this String helper)
        {
            if (helper == null)
                return true;
            else
                return String.Empty == helper.Trim();
        }

        public static int TrimLength(this String helper)
        {
            return helper.Trim().Length;
        }

        /// <summary>
        /// Returns the matched string from the regex pattern. The
        /// groupName is for named group match values in the form (?<name>group).
        /// </summary>
        public static string RegexMatch(this String helper, string pattern, RegexOptions options, string groupName)
        {
            if (groupName.IsNullOrTrimEmpty())
                return Regex.Match(helper, pattern, options).Value;
            else
                return Regex.Match(helper, pattern, options).Groups[groupName].Value;
        }

        public static string RegexMatch(this String helper, string pattern)
        {
            return RegexMatch(helper, pattern, RegexOptions.None, null);
        }

        public static string RegexMatch(this String helper, string pattern, RegexOptions options)
        {
            return RegexMatch(helper, pattern, options, null);
        }

        public static string RegexMatch(this String helper, string pattern, string groupName)
        {
            return RegexMatch(helper, pattern, RegexOptions.None, groupName);
        }

        /// <summary>
        /// Returns true if there is a match from the regex pattern
        /// </summary>
        public static bool IsRegexMatch(this String helper, string pattern, RegexOptions options)
        {
            return helper.RegexMatch(pattern, options).Length > 0;
        }

        public static bool IsRegexMatch(this String helper, string pattern)
        {
            return helper.IsRegexMatch(pattern, RegexOptions.None);
        }

        /// <summary>
        /// Returns a string where matching patterns are replaced by the replacement string.
        /// </summary>
        /// <param name="pattern">The regex pattern for matching the items to be replaced</param>
        /// <param name="replacement">The string to replace matching items</param>
        /// <returns></returns>
        public static string RegexReplace(this String helper, string pattern, string replacement, RegexOptions options)
        {
            return Regex.Replace(helper, pattern, replacement, options);
        }

        public static string RegexReplace(this String helper, string pattern, string replacement)
        {
            return Regex.Replace(helper, pattern, replacement, RegexOptions.None);
        }
    }

    我喜欢做很多regex,所以我认为这些比添加using语句和额外的代码来处理命名组更容易。


    在ASP.NET中,我总是厌倦使用findcontrol,然后必须在引用之前强制转换并检查值是否为空。所以,我添加了一个typarse()方法来控制它,它反映了int32等框架中类似的方法。

    1
    2
    3
    4
    5
    6
    public static bool TryParse<T>(this Control control, string id, out T result)
        where T : Control
    {
        result = control.FindControl(id) as T;
        return result != null;
    }

    现在您可以在ASP.NET Web窗体页中执行此操作:

    1
    2
    3
    4
    5
    Label lbl;
    if (Page.TryParse("Label1", out lbl))
    {
        lbl.Text ="Safely set text";
    }

    一种避免使用out参数的分析模式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public static bool TryParseInt32(this string input, Action<int> action)
    {
        int result;
        if (Int32.TryParse(input, out result))
        {
            action(result);
            return true;
        }
        return false;
    }

    用途:

    1
    2
    if (!textBox.Text.TryParseInt32(number => label.Text = SomeMathFunction(number)))
        label.Text ="Please enter a valid integer";

    如果需要的话,可以将其放到codeplex项目中。


    对于ASP.NET,我使用httpsessionstate的这些扩展来加载会话中的对象。它允许您以干净的方式加载会话对象,如果它们不存在,它将创建并初始化它们。我使用如下两种扩展方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    private bool CreateMode;
    private MyClass SomeClass;

    protected override void OnInit (EventArgs e)
    {
        CreateMode = Session.GetSessionValue<bool> ("someKey1", () => true);
        SomeClass = Session.GetSessionClass<MyClass> ("someKey2", () => new MyClass ()
        {
           MyProperty = 123
        });
    }

    下面是扩展类:

    ZZU1〔5〕


    在指定索引处覆盖字符串的一部分。

    我必须使用一个系统,它期望一些输入值是固定宽度、固定位置字符串。

    1
    2
    3
    4
    public static string Overwrite(this string s, int startIndex, string newStringValue)
    {
      return s.Remove(startIndex, newStringValue.Length).Insert(startIndex, newStringValue);
    }

    所以我可以做到:

    1
    2
    string s = new String(' ',60);
    s = s.Overwrite(7,"NewValue");


    我一直在使用希望在StringBuilder中使用新行的格式,因此下面非常简单的扩展可以节省几行代码:

    1
    2
    3
    4
    5
    6
    7
    public static class Extensions
    {
        public static void AppendLine(this StringBuilder builder,string format, params object[] args)
        {
            builder.AppendLine(string.Format(format, args));
        }
    }

    另一种选择是StringBuilder中的AppendFormat
    或environment.newline。


    泛型尝试:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    class Program
    {
        static void Main(string[] args)
        {
            var z = 0;
            var a = 0.AsDefaultFor(() => 1 / z);
            Console.WriteLine(a);
            Console.ReadLine();
        }
    }

    public static class TryExtensions
    {
        public static T AsDefaultFor<T>(this T @this, Func<T> operation)
        {
            try
            {
                return operation();
            }
            catch
            {
                return @this;
            }
        }
    }

    如果你想的话,把它放到codeplex项目上。


    如果你在会计年度工作的话,有几个有用的扩展

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    /// <summary>
    /// Returns the fiscal year for the passed in date
    /// </summary>
    /// <param name="value">the date</param>
    /// <returns>the fiscal year</returns>
    public static int FiscalYear(this DateTime value)
    {
      int ret = value.Year;
      if (value.Month >= 7) ret++;
      return ret;
    }

    /// <summary>
    /// Returns the fiscal year for the passed in date
    /// </summary>
    /// <param name="value">the date</param>
    /// <returns>the fiscal year</returns>
    public static string FiscalYearString(this DateTime value)
    {
      int fy = FiscalYear(value);
      return"{0}/{1}".Format(fy - 1, fy);
    }

    IEnumerable的一些工具:ToString(格式)、ToString(函数)和Join(分隔符)。

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var names = new[] {"Wagner","Francine","Arthur","Bernardo" };

    names.ToString("Name: {0}
    "
    );
    // Name: Wagner
    // Name: Francine
    // Name: Arthur
    // Name: Bernardo

    names.ToString(name => name.Length > 6 ? String.Format("{0}", name) : String.Empty);
    // Francine Bernardo

    names.Join(" -");
    // Wagner - Francine - Arthur - Bernardo

    扩展:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public static string ToString<T>(this IEnumerable<T> self, string format)
    {
        return self.ToString(i => String.Format(format, i));
    }

    public static string ToString<T>(this IEnumerable<T> self, Func<T, object> function)
    {
        var result = new StringBuilder();

        foreach (var item in self) result.Append(function(item));

        return result.ToString();
    }

    public static string Join<T>(this IEnumerable<T> self, string separator)
    {
        return String.Join(separator, values: self.ToArray());
    }


    内联转换:我喜欢这个小模式。已为布尔值、双精度值和日期时间完成。设计用于遵循C IS和作为操作员。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public static Int32? AsInt32(this string s)
    {
        Int32 value;
        if (Int32.TryParse(s, out value))
            return value;

        return null;
    }

    public static bool IsInt32(this string s)
    {
        return s.AsInt32().HasValue;
    }

    public static Int32 ToInt32(this string s)
    {
        return Int32.Parse(s);
    {


    Whereif()方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    var query = dc.Reviewer
        .Where(r => r.FacilityID == facilityID)
        .WhereIf(CheckBoxActive.Checked, r => r.IsActive);

    public static IEnumerable<TSource> WhereIf<TSource>(
        this IEnumerable<TSource> source,
        bool condition, Func<TSource, bool> predicate)
    {
        if (condition)
            return source.Where(predicate);
        else
            return source;
    }

    public static IQueryable<TSource> WhereIf<TSource>(
        this IQueryable<TSource> source,
        bool condition, Expression<Func<TSource, bool>> predicate)
    {
        if (condition)
            return source.Where(predicate);
        else
            return source;
    }

    我还为where()扩展方法中的索引谓词添加了重载。为了更有趣,添加一个包含附加"else"谓词的口味。


    我喜欢这些nunit断言扩展:http://svn.咖啡因-it.com/openrasta/trunk/src/rasta.testing/assert extensions.cs


    还有一个:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public enum ParseFailBehavior
    {
       ReturnNull,
       ReturnDefault,
       ThrowException
    }

    public static T? ParseNullableEnum<T>(this string theValue, ParseFailBehavior desiredBehavior = ParseFailBehavior.ReturnNull) where T:struct
    {
       T output;
       T? result = Enum.TryParse<T>(theValue, out output)
          ? (T?)output
          : desiredBehavior == ParseFailBehavior.ReturnDefault
             ? (T?)default(T)
             : null;

       if(result == null && desiredBehavior == ParseFailBehavior.ThrowException)
          throw new ArgumentException("Parse Failed for value {0} of enum type {1}".
             FormatWith(theValue, typeof(T).Name));      
    }

    此版本需要.NET 4.0;在3.5中,没有胰蛋白酶和可选参数;您必须尝试捕获Enum.Parse()。它在3.5中仍然是完全可行的(而且更有用的是,Enum.Parse()是oogly和您唯一的其他选项):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public static T? ParseNummableEnum<T>(this string theValue)
    {
        return theValue.ParseNullableEnum<T>(ParseFailBehavior.ReturnNull);
    }

    public static T? ParseNullableEnum<T>(this string theValue,
        ParseFailBehavior desiredBehavior) where T:struct
    {
        try
        {
            return (T?) Enum.Parse(typeof (T), theValue);
        }
        catch (Exception)
        {
            if(desiredBehavior == ParseFailBehavior.ThrowException) throw;
        }

        return desiredBehavior == ParseFailBehavior.ReturnDefault ? (T?)default(T) : null;
    }

    用途:

    1
    2
    3
    4
    5
    //returns null if OptionOne isn't an enum constant
    var myEnum ="OptionOne".ParseNullableEnum<OptionEnum>();

    //guarantees a return value IF the enum has a"zero" constant value (generally a good practice)
    var myEnum ="OptionTwo".ParseNullableEnum<OptionEnum>(ParseFailBehavior.ReturnDefault).Value

    将任何字符串转换为Int32类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // Calls the underlying int.TryParse method to convert a string
    // representation of a number to its 32-bit signed integer equivalent.
    // Returns Zero if conversion fails.
    public static int ToInt32(this string s)
    {
        int retInt;
        int.TryParse(s, out retInt);
        return retInt;
    }

    样品使用:string s ="999";int i = s.ToInt32();


    相当于python的join方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    /// <summary>
    /// same as python 'join'
    /// </summary>
    /// <typeparam name="T">list type</typeparam>
    /// <param name="separator">string separator </param>
    /// <param name="list">list of objects to be ToString'd</param>
    /// <returns>a concatenated list interleaved with separators</returns>
    static public string Join<T>(this string separator, IEnumerable<T> list)
    {
        var sb = new StringBuilder();
        bool first = true;

        foreach (T v in list)
        {
            if (!first)
                sb.Append(separator);
            first = false;

            if (v != null)
                sb.Append(v.ToString());
        }

        return sb.ToString();
    }


    空白规范化非常有用,尤其是在处理用户输入时:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    namespace Extensions.String
    {
        using System.Text.RegularExpressions;

        public static class Extensions
        {
            /// <summary>
            /// Normalizes whitespace in a string.
            /// Leading/Trailing whitespace is eliminated and
            /// all sequences of internal whitespace are reduced to
            /// a single SP (ASCII 0x20) character.
            /// </summary>
            /// <param name="s">The string whose whitespace is to be normalized</param>
            /// <returns>a normalized string</returns>
            public static string NormalizeWS( this string @this )
            {
                string src        = @this ??"" ;
                string normalized = rxWS.Replace( src , m =>{
                      bool isLeadingTrailingWS = ( m.Index == 0 || m.Index+m.Length == src.Length ? true : false ) ;
                      string p                 = ( isLeadingTrailingWS ?"" :"" ) ;
                      return p ;
                    }) ;

                return normalized ;

            }
            private static Regex rxWS = new Regex( @"\s+" ) ;
        }
    }

    有几次,我发现自己想要一些像,我认为,groovy的"安全导航"。

    从http://groovy.codehaus.org/statements:

    If you are walking a complex object
    graph and don't want to have
    NullPointerExceptions thrown you can
    use the ?. operator rather than . to
    perform your navigation.

    def foo = null def bar =
    foo?.something?.myMethod() assert bar
    == null

    那么,您认为为它添加一个扩展方法是一个好主意吗?类似:

    1
    obj.SafelyNavigate(x => x.SomeProperty.MaybeAMethod().AnotherProperty);

    我觉得这会很好,即使它也会带来一些麻烦。

    如果你认为这是个好主意:

    • 您认为对于值类型应该发生什么?,是否返回默认值?投掷?,是否通过泛型约束禁用它?.
    • 吞咽NullReferenceException以实现它会有很大的风险吗?,你有什么建议?,遍历表达式树执行每个调用或成员访问似乎很困难,而且有点过分杀伤力(如果可能的话),不是吗?.

    也许这只是一个坏主意:D,但我认为如果做得好,它会很有用。如果没有什么比这更重要的了,你认为它有价值,我可以试一试,然后再编辑答案。


    这一个还没有完全烤熟,因为我们今天早上刚做出来的。它将为类型生成完整的类定义。对于您有一个大类,并且希望创建一个子集或完整定义但没有访问它的情况,这非常有用。例如,将对象存储在数据库等中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    public static class TypeExtensions
    {
        public static string GenerateClassDefinition(this Type type)
        {
            var properties = type.GetFields();
            var sb = new StringBuilder();
            var classtext = @"private class $name
            {
             $props}"
    ;

            foreach (var p in GetTypeInfo(type))
            {
                sb.AppendFormat("  public {0} {1}", p.Item2, p.Item1).AppendLine(" { get; set; }");
            }

            return classtext.Replace("$name", type.Name).Replace("$props", sb.ToString());
        }

        #region Private Methods
        private static List<Tuple<string, string>> GetTypeInfo(Type type)
        {
            var ret = new List<Tuple<string, string>>();
            var fields = type.GetFields();
            var props = type.GetProperties();

            foreach(var p in props) ret.Add(new Tuple<string, string>(p.Name, TranslateType(p.PropertyType)));    
            foreach(var f in fields) ret.Add(new Tuple<string, string>(f.Name, TranslateType(f.FieldType)));

            return ret;
        }


        private static string TranslateType(Type input)
        {
            string ret;

            if (Nullable.GetUnderlyingType(input) != null)
            {
                ret = string.Format("{0}?", TranslateType(Nullable.GetUnderlyingType(input)));
            }
            else
            {
                switch (input.Name)
                {
                    case"Int32": ret ="int"; break;
                    case"Int64": ret ="long"; break;
                    case"IntPtr": ret ="long"; break;
                    case"Boolean": ret ="bool"; break;
                    case"String":
                    case"Char":
                    case"Decimal":
                        ret = input.Name.ToLower(); break;
                    default: ret = input.Name; break;
                }
            }

            return ret;
        }
        #endregion
    }

    示例用法:

    1
    Process.GetProcesses().First().GetType().GenerateClassDefinition();

    如果使用linqpad:

    1
    Process.GetProcesses().First().GetType().GenerateClassDefinition().Dump();


    怎么样。。。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public static bool IsWinXPOrHigher(this OperatingSystem OS)
    {
      return (OS.Platform == PlatformID.Win32NT)
        && ((OS.Version.Major > 5) || ((OS.Version.Major == 5) && (OS.Version.Minor >= 1)));
    }

    public static bool IsWinVistaOrHigher(this OperatingSystem OS)
    {
      return (OS.Platform == PlatformID.Win32NT)
        && (OS.Version.Major >= 6);
    }

    public static bool IsWin7OrHigher(this OperatingSystem OS)
    {
      return (OS.Platform == PlatformID.Win32NT)
        && ((OS.Version.Major > 6) || ((OS.Version.Major == 6) && (OS.Version.Minor >= 1)));
    }

    public static bool IsWin8OrHigher(this OperatingSystem OS)
    {
      return (OS.Platform == PlatformID.Win32NT)
        && ((OS.Version.Major > 6) || ((OS.Version.Major == 6) && (OS.Version.Minor >= 2)));
    }

    用途:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    if (Environment.OSVersion.IsWinXPOrHigher())
    {
      // do stuff
    }

    if (Environment.OSVersion.IsWinVistaOrHigher())
    {
      // do stuff
    }

    if (Environment.OSVersion.IsWin7OrHigher())
    {
      // do stuff
    }

    if (Environment.OSVersion.IsWin8OrHigher())
    {
      // do stuff
    }

    我使用以下扩展扩展扩展所有集合(可能有人发现这些有用):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    /// <summary>
    /// Collection Helper
    /// </summary>
    /// <remarks>
    /// Use IEnumerable by default, but when altering or getting item at index use IList.
    /// </remarks>
    public static class CollectionHelper
    {

        #region Alter;

        /// <summary>
        /// Swap item to another place
        /// </summary>
        /// <typeparam name="T">Collection type</typeparam>
        /// <param name="this">Collection</param>
        /// <param name="IndexA">Index a</param>
        /// <param name="IndexB">Index b</param>
        /// <returns>New collection</returns>
        public static IList<T> Swap<T>(this IList<T> @this, Int32 IndexA, Int32 IndexB)
        {
            T Temp = @this[IndexA];
            @this[IndexA] = @this[IndexB];
            @this[IndexB] = Temp;
            return @this;
        }

        /// <summary>
        /// Swap item to the left
        /// </summary>
        /// <typeparam name="T">Collection type</typeparam>
        /// <param name="this">Collection</param>
        /// <param name="Index">Index</param>
        /// <returns>New collection</returns>
        public static IList<T> SwapLeft<T>(this IList<T> @this, Int32 Index)
        {
            return @this.Swap(Index, Index - 1);
        }

        /// <summary>
        /// Swap item to the right
        /// </summary>
        /// <typeparam name="T">Collection type</typeparam>
        /// <param name="this">Collection</param>
        /// <param name="Index">Index</param>
        /// <returns>New collection</returns>
        public static IList<T> SwapRight<T>(this IList<T> @this, Int32 Index)
        {
            return @this.Swap(Index, Index + 1);
        }

        #endregion Alter;

        #region Action;

        /// <summary>
        /// Execute action at specified index
        /// </summary>
        /// <typeparam name="T">Collection type</typeparam>
        /// <param name="this">Collection</param>
        /// <param name="Index">Index</param>
        /// <param name="ActionAt">Action to execute</param>
        /// <returns>New collection</returns>
        public static IList<T> ActionAt<T>(this IList<T> @this, Int32 Index, Action<T> ActionAt)
        {
            ActionAt(@this[Index]);
            return @this;
        }

        #endregion Action;

        #region Randomize;

        /// <summary>
        /// Take random items
        /// </summary>
        /// <typeparam name="T">Collection type</typeparam>
        /// <param name="this">Collection</param>
        /// <param name="Count">Number of items to take</param>
        /// <returns>New collection</returns>
        public static IEnumerable<T> TakeRandom<T>(this IEnumerable<T> @this, Int32 Count)
        {
            return @this.Shuffle().Take(Count);
        }

        /// <summary>
        /// Take random item
        /// </summary>
        /// <typeparam name="T">Collection type</typeparam>
        /// <param name="this">Collection</param>
        /// <returns>Item</returns>
        public static T TakeRandom<T>(this IEnumerable<T> @this)
        {
            return @this.TakeRandom(1).Single();
        }

        /// <summary>
        /// Shuffle list
        /// </summary>
        /// <typeparam name="T">Collection type</typeparam>
        /// <param name="this">Collection</param>
        /// <returns>New collection</returns>
        public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> @this)
        {
            return @this.OrderBy(Item => Guid.NewGuid());
        }

        #endregion Randomize;

        #region Navigate;

        /// <summary>
        /// Get next item in collection and give first item, when last item is selected;
        /// </summary>
        /// <typeparam name="T">Collection type</typeparam>
        /// <param name="this">Collection</param>
        /// <param name="Index">Index in collection</param>
        /// <returns>Next item</returns>
        public static T Next<T>(this IList<T> @this, ref Int32 Index)
        {
            Index = ++Index >= 0 && Index < @this.Count ? Index : 0;
            return @this[Index];
        }

        /// <summary>
        /// Get previous item in collection and give last item, when first item is selected;
        /// </summary>
        /// <typeparam name="T">Collection type</typeparam>
        /// <param name="this">Collection</param>
        /// <param name="Index">Index in collection</param>
        /// <returns>Previous item</returns>
        public static T Previous<T>(this IList<T> @this, ref Int32 Index)
        {
            Index = --Index >= 0 && Index < @this.Count ? Index : @this.Count - 1;
            return @this[Index];
        }

        #endregion Navigate;

        #region Clone;

        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T">Collection type</typeparam>
        /// <param name="this">Collection</param>
        /// <returns>Cloned collection</returns>
        public static IEnumerable<T> Clone<T>(this IEnumerable<T> @this) where T : ICloneable
        {
            return @this.Select(Item => (T)Item.Clone());
        }

        #endregion Clone;

        #region String;

        /// <summary>
        /// Joins multiple string with Separator
        /// </summary>
        /// <param name="this">Collection</param>
        /// <param name="Separator">Separator</param>
        /// <returns>Joined string</returns>
        public static String Join(this IEnumerable<String> @this, String Separator ="")
        {
            return String.Join(Separator, @this);
        }

        #endregion String;

    }

    在序列化和配置时,最好使用long as-datetime,因此:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
        public static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0);

        public static long ToUnixTimestamp(this DateTime dateTime)
        {
            return (long) (dateTime - Epoch).TotalSeconds;
        }

        public static long ToUnixUltraTimestamp(this DateTime dateTime)
        {
            return (long) (dateTime - Epoch).TotalMilliseconds;
        }

    向后

    1
    2
    3
    4
    5
    6
    7
    8
    9
        public static DateTime ToDateTime(this long unixDateTime)
        {
            return Epoch.AddSeconds(unixDateTime);
        }

        public static DateTime ToDateTimeUltra(this long unixUltraDateTime)
        {
            return Epoch.AddMilliseconds(unixUltraDateTime);
        }

    如果需要检查字符串的is all char为0:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     static public bool   IsAllZero            (this string input)
            {
                if(string.IsNullOrEmpty(input))
                    return true;
                foreach (char ch in input)
                {
                    if(ch != '0')
                        return false;
                }
                return true;
            }


    如果您使用波斯语,并且必须以波斯语向用户显示数字:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    static public string ToFaString         (this string value)
            {
                // 1728 , 1584
                string result ="";
                if (value != null)
                {
                    char[] resChar = value.ToCharArray();
                    for (int i = 0; i < resChar.Length; i++)
                    {
                        if (resChar[i] >= '0' && resChar[i] <= '9')
                            result += (char)(resChar[i] + 1728);
                        else
                            result += resChar[i];
                    }
                }
                return result;
            }


    我们有一个部署工具可以在环境之间部署。由于文件可以标记为"已修改",但实际上没有不同,所以我想到了以下方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    /// <summary>
    /// Compares the files to see if they are different.
    /// First checks file size
    /// Then modified if the file is larger than the specified size
    /// Then compares the bytes
    /// </summary>
    /// <param name="file1">The source file</param>
    /// <param name="file2">The destination file</param>
    /// <param name="mb">Skip the smart check if the file is larger than this many megabytes. Default is 10.</param>
    /// <returns></returns>
    public static bool IsDifferentThan(this FileInfo file1, FileInfo file2, int mb = 10)
    {
      var ret = false;

      // different size is a different file
      if(file1.Length != file2.Length) return true;

      // if the file times are different and the file is bigger than 10mb flag it for updating
      if(file1.LastWriteTimeUtc > file2.LastWriteTimeUtc && file1.Length > ((mb*1024)*1024)) return true;

      var f1 = File.ReadAllBytes(file1.FullName);
      var f2 = File.ReadAllBytes(file2.FullName);

      // loop through backwards because if they are different
      // it is more likely that the last few bytes will be different
      // than the first few
      for(var i = file1.Length - 1; i > 0; i--)
      {
        if(f1[i] != f2[i])
        {
          ret = true;
          break;
        }
      }

      return ret;
    }

    SQL Server的参数限制为~2000个,如果您有10000个ID,并且希望将这些记录与其连接,这会很麻烦。我编写了这些方法,它们接受成批的ID列表,并按如下方式调用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    List<Order> orders = dataContext.Orders.FetchByIds(
      orderIdChunks,
      list => row => list.Contains(row.OrderId)
    );

    List<Customer> customers = dataContext.Orders.FetchByIds(
      orderIdChunks,
      list => row => list.Contains(row.OrderId),
      row => row.Customer
    );

    public static List<ResultType> FetchByIds<RecordType, ResultType>(
        this IQueryable<RecordType> querySource,
        List<List<int>> IdChunks,
        Func<List<int>, Expression<Func<RecordType, bool>>> filterExpressionGenerator,
        Expression<Func<RecordType, ResultType>> projectionExpression
        ) where RecordType : class
    {
        List<ResultType> result = new List<ResultType>();
        foreach (List<int> chunk in IdChunks)
        {
            Expression<Func<RecordType, bool>> filterExpression =
                filterExpressionGenerator(chunk);

            IQueryable<ResultType> query = querySource
                .Where(filterExpression)
                .Select(projectionExpression);

            List<ResultType> rows = query.ToList();
            result.AddRange(rows);
        }

        return result;
    }

    public static List<RecordType> FetchByIds<RecordType>(
        this IQueryable<RecordType> querySource,
        List<List<int>> IdChunks,
        Func<List<int>, Expression<Func<RecordType, bool>>> filterExpressionGenerator
        ) where RecordType : class
    {
        Expression<Func<RecordType, RecordType>> identity = r => r;

        return FetchByIds(
            querySource,
            IdChunks,
            filterExpressionGenerator,
            identity
            );
    }

    比较两个对象的相等性,不要(必须)重写equals或实现iequatable<>。

    你为什么要这么做?当你真的想知道两个对象是否相等,但是你太懒了,不能重写Equals(object)或实现IEquatable。或者,更现实地说,如果您有一个非常复杂的类,并且手工实现equals,那么这将是非常繁琐的、容易出错的,并且维护起来并不有趣。如果你不太关心性能,这也会有帮助。

    由于第二个原因,我目前正在使用IsEqualTo—我有一个类,它有许多属性,它们的类型是其他用户定义类,每个属性都有许多其他属性,它们的类型是其他用户定义类,无限。在许多这些类中加入一堆集合,实现Equals(object)真的是一场噩梦。

    用途:

    1
    2
    3
    4
    if (myTerriblyComplexObject.IsEqualTo(myOtherTerriblyComplexObject))
    {
        // Do something terribly interesting.
    }

    为了确定平等,我做了很多比较。我尽力按"正确"的顺序做"正确"的事情。比较顺序如下:

  • 使用静态Equals(object, object)方法。如果返回真,则返回真。如果引用相同,则返回true。如果thisObject覆盖Equals(object),它也将返回真值。
  • 如果thisObject为空,则返回false。如果为空,则无法进行进一步的比较。
  • 如果thisObject已覆盖Equals(object),则返回false。因为它重写equals,所以它必须意味着equals是在步骤1执行的,并返回false。如果有人费心重写equals,我们应该尊重它并返回equals返回的值。
  • 如果thisObject继承IEquatable,其中otherObject可以分配给T,则使用反射得到Equals(T)方法。调用该方法并返回其返回值。
  • 如果两个对象都是IEnumerable,返回是否包含相同的项目,顺序相同,使用isequal比较项目。
  • 如果对象具有不同的类型,则返回false。既然我们现在知道thisObject没有一个相等的方法,就没有任何方法来实际地评价两个不同类型的对象是真的。
  • 如果对象是值类型(基元或结构)或字符串,则返回false。我们已经通过了Equals(object)测试——够了。
  • 对于thisObject的每一个属性,用等量检验其值。如果有返回假,则返回假。如果全部返回真,则返回真。
  • 字符串比较可能更好,但易于实现。另外,我不能百分之百确定我处理结构是否正确。

    不需要进一步的ADO,这里是扩展方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    /// <summary>
    /// Provides extension methods to determine if objects are equal.
    /// </summary>
    public static class EqualsEx
    {
        /// <summary>
        /// The <see cref="Type"/> of <see cref="string"/>.
        /// </summary>
        private static readonly Type StringType = typeof(string);

        /// <summary>
        /// The <see cref="Type"/> of <see cref="object"/>.
        /// </summary>
        private static readonly Type ObjectType = typeof(object);

        /// <summary>
        /// The <see cref="Type"/> of <see cref="IEquatable{T}"/>.
        /// </summary>
        private static readonly Type EquatableType = typeof(IEquatable<>);

        /// <summary>
        /// Determines whether <paramref name="thisObject"/> is equal to <paramref name="otherObject"/>.
        /// </summary>
        /// <param name="thisObject">
        /// This object.
        /// </param>
        /// <param name="otherObject">
        /// The other object.
        /// </param>
        /// <returns>
        /// True, if they are equal, otherwise false.
        /// </returns>
        public static bool IsEqualTo(this object thisObject, object otherObject)
        {
            if (Equals(thisObject, otherObject))
            {
                // Always check Equals first. If the object has overridden Equals, use it. This will also capture the case where both are the same reference.
                return true;
            }

            if (thisObject == null)
            {
                // Because Equals(object, object) returns true if both are null, if either is null, return false.
                return false;
            }

            var thisObjectType = thisObject.GetType();
            var equalsMethod = thisObjectType.GetMethod("Equals", BindingFlags.Public | BindingFlags.Instance, null, new[] { ObjectType }, null);
            if (equalsMethod.DeclaringType == thisObjectType)
            {
                // thisObject overrides Equals, and we have already failed the Equals test, so return false.
                return false;
            }

            var otherObjectType = otherObject == null ? null : otherObject.GetType();

            // If thisObject inherits from IEquatable<>, and otherObject can be passed into its Equals method, use it.
            var equatableTypes = thisObjectType.GetInterfaces().Where(                                          // Get interfaces of thisObjectType that...
                i => i.IsGenericType                                                                            // ...are generic...
                && i.GetGenericTypeDefinition() == EquatableType                                                // ...and are IEquatable of some type...
                && (otherObjectType ==  null || i.GetGenericArguments()[0].IsAssignableFrom(otherObjectType))); // ...and otherObjectType can be assigned to the IEquatable's type.

            if (equatableTypes.Any())
            {
                // If we found any interfaces that meed our criteria, invoke the Equals method for each interface.
                // If any return true, return true. If all return false, return false.
                return equatableTypes
                    .Select(equatableType => equatableType.GetMethod("Equals", BindingFlags.Public | BindingFlags.Instance))
                    .Any(equatableEqualsMethod => (bool)equatableEqualsMethod.Invoke(thisObject, new[] { otherObject }));
            }

            if (thisObjectType != StringType && thisObject is IEnumerable && otherObject is IEnumerable)
            {
                // If both are IEnumerable, check their items.
                var thisEnumerable = ((IEnumerable)thisObject).Cast<object>();
                var otherEnumerable = ((IEnumerable)otherObject).Cast<object>();

                return thisEnumerable.SequenceEqual(otherEnumerable, IsEqualToComparer.Instance);
            }

            if (thisObjectType != otherObjectType)
            {
                // If they have different types, they cannot be equal.
                return false;
            }

            if (thisObjectType.IsValueType || thisObjectType == StringType)
            {
                // If it is a value type, we have already determined that they are not equal, so return false.
                return false;
            }

            // Recurse into each public property: if any are not equal, return false. If all are true, return true.
            return !(from propertyInfo in thisObjectType.GetProperties()
                     let thisPropertyValue = propertyInfo.GetValue(thisObject, null)
                     let otherPropertyValue = propertyInfo.GetValue(otherObject, null)
                     where !thisPropertyValue.IsEqualTo(otherPropertyValue)
                     select thisPropertyValue).Any();
        }

        /// <summary>
        /// A <see cref="IEqualityComparer{T}"/> to be used when comparing sequences of collections.
        /// </summary>
        private class IsEqualToComparer : IEqualityComparer<object>
        {
            /// <summary>
            /// The singleton instance of <see cref="IsEqualToComparer"/>.
            /// </summary>
            public static readonly IsEqualToComparer Instance;

            /// <summary>
            /// Initializes static members of the <see cref="EqualsEx.IsEqualToComparer"/> class.
            /// </summary>
            static IsEqualToComparer()
            {
                Instance = new IsEqualToComparer();
            }

            /// <summary>
            /// Prevents a default instance of the <see cref="EqualsEx.IsEqualToComparer"/> class from being created.
            /// </summary>
            private IsEqualToComparer()
            {
            }

            /// <summary>
            /// Determines whether the specified objects are equal.
            /// </summary>
            /// <param name="x">
            /// The first object to compare.
            /// </param>
            /// <param name="y">
            /// The second object to compare.
            /// </param>
            /// <returns>
            /// true if the specified objects are equal; otherwise, false.
            /// </returns>
            bool IEqualityComparer<object>.Equals(object x, object y)
            {
                return x.IsEqualTo(y);
            }

            /// <summary>
            /// Not implemented - throws an <see cref="NotImplementedException"/>.
            /// </summary>
            /// <param name="obj">
            /// The <see cref="object"/> for which a hash code is to be returned.
            /// </param>
            /// <returns>
            /// A hash code for the specified object.
            /// </returns>
            int IEqualityComparer<object>.GetHashCode(object obj)
            {
                throw new NotImplementedException();
            }
        }
    }

    这里是我经常使用的控件调用扩展;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public static class InvokeExtensions
    {
        public static void InvokeHandler(this Control control, MethodInvoker del) // Sync. control-invoke extension.
        {
            if (control.InvokeRequired)
            {
                control.Invoke(del);
                return;
            }
            del(); // run the actual code.
        }

        public static void AsyncInvokeHandler(this Control control, MethodInvoker del) // Async. control-invoke extension.
        {
            if (control.InvokeRequired)
            {
                control.BeginInvoke(del);
                return;
            }
            del(); // run the actual code.
        }
    }

    样品;

    1
    2
    3
    4
    this.TreeView.AsyncInvokeHandler(() =>
            {
                this.Text = 'xyz'
            });

    允许跨线程GUI更新。


    为什么不呢?这里有一个IList的扩展(不能是IEnumerable,因为我使用了特定于列表的功能)来进行插入排序。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    internal static class SortingHelpers
    {
        /// <summary>
        /// Performs an insertion sort on this list.
        /// </summary>
        /// <typeparam name="T">The type of the list supplied.</typeparam>
        /// <param name="list">the list to sort.</param>
        /// <param name="comparison">the method for comparison of two elements.</param>
        /// <returns></returns>
        public static void InsertionSort<T>(this IList<T> list, Comparison<T> comparison)
        {
            for (int i = 2; i < list.Count; i++)
            {
                for (int j = i; j > 1 && comparison(list[j], list[j - 1]) < 0; j--)
                {
                    T tempItem = list[j];
                    list.RemoveAt(j);
                    list.Insert(j - 1, tempItem);
                }
            }
        }
    }

    一个例子:

    1
    2
    3
    List<int> list1 = { 3, 5, 1, 2, 9, 4, 6 };
    list1.InsertionSort((a,b) => a - b);
    //list is now in order of 1,2,3,4,5,6,9


    C中的smalltalk-style if/else。

    无论您使用什么许可证,都可以将其放到codeplex上。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    using System;
    namespace SmalltalkBooleanExtensionMethods
    {

        public static class BooleanExtension
        {
            public static T ifTrue<T> (this bool aBoolean, Func<T> method)
            {
            if (aBoolean)
                return (T)method();
            else
                return default(T);
        }

            public static void ifTrue (this bool aBoolean, Action method)
            {
                if (aBoolean)
                    method();
            }


            public static T ifFalse<T> (this bool aBoolean, Func<T> method)
            {
                if (!aBoolean)
                    return (T)method();
                else
                    return default(T);
            }

            public static void ifFalse (this bool aBoolean, Action method)
            {
                if (!aBoolean)
                    method();
            }


            public static T ifTrueifFalse<T> (this Boolean aBoolean, Func<T> methodA, Func<T> methodB)
            {
                if (aBoolean)
                    return (T)methodA();
                else
                    return (T)methodB();
            }

            public static void ifTrueifFalse (this Boolean aBoolean, Action methodA, Action methodB)
            {
                if (aBoolean)
                    methodA();
                else
                    methodB();
            }

        }


    }

    您可能已经有了timerepeat方法,但它就在其中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    using System;

    namespace SmalltalkBooleanExtensionMethods
    {
        public static class IntExtension
        {
            public static int timesRepeat<T>(this int x, Func<T> method)
            {
                for (int i = x; i > 0; i--)
                {
                    method();
                }

                return x;
            }

            public static int timesRepeat(this int x, Action method)
            {
                for (int i = x; i > 0; i--)
                {
                    method();
                }

                return x;
            }
        }
    }

    非单位检验

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    using System;
    using SmalltalkBooleanExtensionMethods;
    using NUnit.Framework;

    namespace SmalltalkBooleanExtensionMethodsTest
    {
        [TestFixture]
        public class SBEMTest
        {
            int i;
            bool itWorks;

            [SetUp]
            public void Init()
            {

                i = 0;
                itWorks = false;
            }

            [Test()]
            public void TestifTrue()
            {

                itWorks = (true.ifTrue(() => true));
                Assert.IsTrue(itWorks);
            }
            [Test()]
            public void TestifFalse()
            {
                itWorks = (false.ifFalse(() => true));
                Assert.IsTrue(itWorks);
            }

            [Test()]
            public void TestifTrueifFalse()
            {
                itWorks = false.ifTrueifFalse(() => false, () => true);
                Assert.IsTrue(itWorks);
                itWorks = false;
                itWorks = true.ifTrueifFalse(() => true, () => false);
                Assert.IsTrue(itWorks);
            }

            [Test()]
            public void TestTimesRepeat()
            {
                (5).timesRepeat(() => i = i + 1);
                Assert.AreEqual(i, 5);
            }

            [Test()]
            public void TestVoidMethodIfTrue()
            {

                true.ifTrue(() => SetItWorksBooleanToTrue());
                Assert.IsTrue(itWorks);
            }

            [Test()]
            public void TestVoidMethodIfFalse()
            {

                false.ifFalse(() => SetItWorksBooleanToTrue());
                Assert.IsTrue(itWorks);
            }

            public void TestVoidMethodIfTrueIfFalse()
            {
                true.ifTrueifFalse(() => SetItWorksBooleanToTrue(), () => SetItWorksBooleanToFalse());
                false.ifTrueifFalse(() => SetItWorksBooleanToFalse(), () => SetItWorksBooleanToTrue());
                Assert.IsTrue(itWorks);

            }

            public void TestVoidMethodTimesRepeat()
            {
                (5).timesRepeat(() => AddOneToi());
                Assert.AreEqual(i, 5);
            }

            public void SetItWorksBooleanToTrue()
            {
                itWorks = true;
            }

            public void SetItWorksBooleanToFalse()
            {
                itWorks = false;
            }

            public void AddOneToi()
            {
                i = i + 1;
            }
        }
    }


    • 用于向没有addrange的集合中添加多个元素,例如collection.Add(item1, item2, itemN);

      1
      2
      3
      static void Add<T>(this ICollection<T> coll, params T[] items)
       { foreach (var item in items) coll.Add(item);
       }
    • 以下类似于string.Format(),但使用参数的自定义字符串表示,例如,"{0} {1} {2}".Format(c=>c.Name,"string",new object(),new Custom())会导致"string {System.Object} Custom1Name"

      1
      2
      3
      4
      5
      6
      7
      8
      9
      static string Format<T>(  this string format
                              , Func<T,object> select
                              , params object[] args)
       { for(int i=0; i < args.Length; ++i)
          { var x = args[i] as T;
            if (x != null) args[i] = select(x);
          }
         return string.Format(format, args);
       }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    // This file contains extension methods for generic List<> class to operate on sorted lists.
    // Duplicate values are OK.
    // O(ln(n)) is still much faster then the O(n) of LINQ's searches/filters.
    static partial class SortedList
    {
        // Return the index of the first element with the key greater then provided.
        // If there's no such element within the provided range, it returns iAfterLast.
        public static int sortedFirstGreaterIndex<tElt, tKey>( this IList<tElt> list, Func<tElt, tKey, int> comparer, tKey key, int iFirst, int iAfterLast )
        {
            if( iFirst < 0 || iAfterLast < 0 || iFirst > list.Count || iAfterLast > list.Count )
                throw new IndexOutOfRangeException();
            if( iFirst > iAfterLast )
                throw new ArgumentException();
            if( iFirst == iAfterLast )
                return iAfterLast;

            int low = iFirst, high = iAfterLast;
            // The code below is inspired by the following article:
            // http://en.wikipedia.org/wiki/Binary_search#Single_comparison_per_iteration
            while( low < high )
            {
                int mid = ( high + low ) / 2;
                // 'mid' might be 'iFirst' in case 'iFirst+1 == iAfterLast'.
                // 'mid' will never be 'iAfterLast'.
                if( comparer( list[ mid ], key ) <= 0 ) //"<=" since we gonna find the first"greater" element
                    low = mid + 1;
                else
                    high = mid;
            }
            return low;
        }

        // Return the index of the first element with the key greater then the provided key.
        // If there's no such element, returns list.Count.
        public static int sortedFirstGreaterIndex<tElt, tKey>( this IList<tElt> list, Func<tElt, tKey, int> comparer, tKey key )
        {
            return list.sortedFirstGreaterIndex( comparer, key, 0, list.Count );
        }

        // Add an element to the sorted array.
        // This could be an expensive operation if frequently adding elements that sort firstly.
        // This is cheap operation when adding elements that sort near the tail of the list.
        public static int sortedAdd<tElt>( this List<tElt> list, Func<tElt, tElt, int> comparer, tElt elt )
        {
            if( list.Count == 0 || comparer( list[ list.Count - 1 ], elt ) <= 0 )
            {
                // either the list is empty, or the item is greater then all elements already in the collection.
                list.Add( elt );
                return list.Count - 1;
            }
            int ind = list.sortedFirstGreaterIndex( comparer, elt );
            list.Insert( ind, elt );
            return ind;
        }

        // Find first exactly equal element, return -1 if not found.
        public static int sortedFindFirstIndex<tElt, tKey>( this List<tElt> list, Func<tElt, tKey, int> comparer, tKey elt )
        {
            int low = 0, high = list.Count - 1;

            while( low < high )
            {
                int mid = ( high + low ) / 2;
                if( comparer( list[ mid ], elt ) < 0 )
                    low = mid + 1;
                else
                    high = mid; // this includes the case when we've found an element exactly matching the key
            }
            if( high >= 0 && 0 == comparer( list[ high ], elt ) )
                return high;
            return -1;
        }

        // Return the IEnumerable that returns array elements in the reverse order.
        public static IEnumerable<tElt> sortedReverse<tElt>( this List<tElt> list )
        {
            for( int i=list.Count - 1; i >= 0; i-- )
                yield return list[ i ];
        }
    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public static class DictionaryExtensions
    {
        public static Nullable<TValue> GetValueOrNull<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key)
            where TValue : struct
        {
            TValue result;
            if (dictionary.TryGetValue(key, out result))
                return result;
            else
                return null;
        }
    }

    免费使用,只要提到我的名字(Janko R?在代码中。


    1
    2
    3
    4
    5
    6
    7
    public static class StringHelper
    {
        public static String F(this String str, params object[] args)
        {
            return String.Format(str, args);
        }
    }

    使用如下:

    1
    "Say {0}".F("Hello");


    一些数据集/数据行扩展,使使用DB结果更简单

    只需在数据行上使用.field("fieldname"),如果可以,它将对其进行强制转换,可以包括可选的默认值。

    还可以在数据集中使用.hasRows(),这样就不需要检查表和行的存在性。

    例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    using (DataSet ds = yourcall())
    {
      if (ds.HasRows())
      {
         foreach (DataRow dr in ds.Tables[0].Rows)
         {
            int id = dr.Field<int>("ID");
            string name = dr.Field<string>("Name");
            string Action = dr.Field<string>("Action","N/A");
         }
      }
    }

    代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    using System;
    using System.Data;

    public static class DataSetExtensions
    {
        public static T Field<T>(this DataRow row, string columnName, T defaultValue)
        {
            try
            {
                return row.Field<T>(columnName);
            }
            catch
            {
                return defaultValue;
            }
        }

        public static T Field<T>(this DataRow row, string columnName)
        {
            if (row[columnName] == null)
                throw new NullReferenceException(columnName +" does not exist in DataRow");

            string value = row[columnName].ToString();

            if (typeof(T) =="".GetType())
            {
                return (T)Convert.ChangeType(value, typeof(T));
            }
            else if (typeof(T) == 0.GetType())
            {
                return (T)Convert.ChangeType(int.Parse(value), typeof(T));
            }
            else if (typeof(T) == false.GetType())
            {
                return (T)Convert.ChangeType(bool.Parse(value), typeof(T));
            }
            else if (typeof(T) == DateTime.Now.GetType())
            {
                return (T)Convert.ChangeType(DateTime.Parse(value), typeof(T));
            }
            else if (typeof(T) == new byte().GetType())
            {
                return (T)Convert.ChangeType(byte.Parse(value), typeof(T));
            }
            else if (typeof(T) == new float().GetType())
            {
                return (T)Convert.ChangeType(float.Parse(value), typeof(T));
            }
            else
            {
                throw new ArgumentException(string.Format("Cannot cast '{0}' to '{1}'.", value, typeof(T).ToString()));
            }
        }

        public static bool HasRows(this DataSet dataSet)
        {
            return (dataSet.Tables.Count > 0 && dataSet.Tables[0].Rows.Count > 0);
        }
    }


    另一个,这次是为了在处理查询参数时使uribuilder更友好。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
        /// <summary>
        /// Adds the specified query parameter to the URI builder.
        /// </summary>
        /// <param name="builder">The builder.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <param name="value">The URI escaped value.</param>
        /// <returns>The final full query string.</returns>
        public static string AddQueryParam(this UriBuilder builder, string parameterName, string value)
        {
            if (parameterName == null)
                throw new ArgumentNullException("parameterName");

            if (parameterName.Length == 0)
                throw new ArgumentException("The parameter name is empty.");

            if (value == null)
                throw new ArgumentNullException("value");

            if (value.Length == 0)
                throw new ArgumentException("The value is empty.");

            if (builder.Query.Length == 0)
            {
                builder.Query = String.Concat(parameterName,"=", value);
            }
            else if
                (builder.Query.Contains(String.Concat("&", parameterName,"="))
                || builder.Query.Contains(String.Concat("?", parameterName,"=")))
            {
                throw new InvalidOperationException(String.Format("The parameter {0} already exists.", parameterName));
            }
            else
            {
                builder.Query = String.Concat(builder.Query.Substring(1),"&", parameterName,"=", value);
            }

            return builder.Query;
        }

    在我的博客统计页面的最近搜索部分,我删除了所有重复的内容,但需要一种方法来删除几乎重复的内容。我会得到大量类似的,但不完全相同的谷歌查询。

    我最终使用的是匿名类型而不是字典,但我想找到一种方法来创建该匿名类型的列表。不能这样做,但可以在.NET 4.0中创建List

    大部分我喜欢它,因为我实际上得到了一个List()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    /// <summary>Remove extraneous entries for common word permutations</summary>
    /// <param name="input">Incoming series of words to be filtered</param>
    /// <param name="MaxIgnoreLength">Words this long or shorter will not count as duplicates</param>
    /// <param name="words2">Instance list from BuildInstanceList()</param>
    /// <returns>Filtered list of lines from input, based on filter info in words2</returns>
    private static List<string> FilterNearDuplicates(List<string> input, int MaxIgnoreLength, List<dynamic> words2)
    {
        List<string> output = new List<string>();
        foreach (string line in input)
        {
            int Dupes = 0;
            foreach (string word in line.Split(new char[] { ' ', ',', ';', '\', '/', ':', '"', '
    ', '
    ', '.' })
                .Where(p => p.Length > MaxIgnoreLength)
                .Distinct())
            {
                int Instances = 0;
                foreach (dynamic dyn in words2)
                if (word == dyn.Word)
                {
                    Instances = dyn.Instances;
                    if (Instances > 1)
                        Dupes++;
                    break;
                }
            }
            if (Dupes == 0)
                output.Add(line);
        }
        return output;
    }
    /// <summary>Builds a list of words and how many times they occur in the overall list</summary>
    /// <param name="
    input">Incoming series of words to be counted</param>
    /// <returns></returns>
    private static List<dynamic> BuildInstanceList(List<string> input)
    {
        List<dynamic> words2 = new List<object>();
        foreach (string line in input)
        foreach (string word in line.Split(new char[] { ' ', ',', ';', '\', '/', ':', '"
    ', '
    ', '
    ', '.' }))
        {
            if (string.IsNullOrEmpty(word))
                continue;
            else if (ExistsInList(word, words2))
                for (int i = words2.Count - 1; i >= 0; i--)
                {
                    if (words2[i].Word == word)
                        words2[i] = new { Word = words2[i].Word, Instances = words2[i].Instances + 1 };
                }
            else
                words2.Add(new { Word = word, Instances = 1 });
        }

        return words2;
    }
    /// <summary>Determines whether a dynamic Word object exists in a List of this dynamic type.</summary>
    /// <param name="word">Word to look for</param>
    /// <param name="words">Word dynamics to search through</param>
    /// <returns>Indicator of whether the word exists in the list of words</returns>
    private static bool ExistsInList(string word, List<dynamic> words)
    {
        foreach (dynamic dyn in words)
            if (dyn.Word == word)
                return true;
        return false;
    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // Checks for an empty collection, and sends the value set in the default constructor for the desired field
    public static TResult MinGuarded<T, TResult>(this IEnumerable<T> items, Func<T, TResult> expression) where T : new() {
        if(items.IsEmpty()) {
            return (new List<T> { new T() }).Min(expression);
        }
        return items.Min(expression);
    }

    // Checks for an empty collection, and sends the value set in the default constructor for the desired field
    public static TResult MaxGuarded<T, TResult>(this IEnumerable<T> items, Func<T, TResult> expression) where T : new() {
        if(items.IsEmpty()) {
            return (new List<T> { new T() }).Max(expression);
        }
        return items.Max(expression);
    }

    我不确定是否有更好的方法可以做到这一点,但是只要我想控制对象中字段的默认值,这个扩展就非常有用。例如,如果我想要控制日期时间的值,并且想要根据我的业务逻辑进行设置,那么我可以在默认的构造函数中这样做。否则,结果是DateTime.MinDate


    也许我编写和使用的最有用的扩展方法是:

    http://www.codeproject.com/kb/cs/fun-with-cs-extensions.aspx?消息=2838918 XX2838918XX


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    // Values ordered true/false
    // True/false values separated by a capital letter
    // Only two values allowed
    // ---------------------------
    // Limited, but could be useful
    public enum BooleanFormat
    {
        OneZero,
        YN,
        YesNo,
        TF,
        TrueFalse,
        PassFail,
        YepNope
    }

    public static class BooleanExtension
    {
        /// <summary>
        /// Converts the boolean value of this instance to the specified string value.
        /// </summary>
        private static string ToString(this bool value, string passValue, string failValue)
        {
            return value ? passValue : failValue;
        }

        /// <summary>
        /// Converts the boolean value of this instance to a string.
        /// </summary>
        /// <param name="booleanFormat">A BooleanFormat value.
        /// Example: BooleanFormat.PassFail would return"Pass" if true and"Fail" if false.</param>
        /// <returns>Boolean formatted string</returns>
        public static string ToString(this bool value, BooleanFormat booleanFormat)
        {
            string booleanFormatString = Enum.GetName(booleanFormat.GetType(), booleanFormat);
            return ParseBooleanString(value, booleanFormatString);      
        }

        // Parses boolean format strings, not optimized
        private static string ParseBooleanString(bool value, string booleanFormatString)
        {
            StringBuilder trueString = new StringBuilder();
            StringBuilder falseString = new StringBuilder();

            int charCount = booleanFormatString.Length;

            bool isTrueString = true;

            for (int i = 0; i != charCount; i++)
            {
                if (char.IsUpper(booleanFormatString[i]) && i != 0)
                    isTrueString = false;

                if (isTrueString)
                    trueString.Append(booleanFormatString[i]);
                else
                    falseString.Append(booleanFormatString[i]);
            }

            return (value == true ? trueString.ToString() : falseString.ToString());
        }


    我创建了一个扩展方法来选择ASP.NET下拉列表中的项。

    下面是代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     public static class Utilities
    {
        public enum DropDownListSelectionType
        {
            ByValue,
            ByText
        }

        public static void SelectItem(this  System.Web.UI.WebControls.DropDownList drp, string selectedValue, DropDownListSelectionType type)
        {
            drp.ClearSelection();
            System.Web.UI.WebControls.ListItem li;
            if (type == DropDownListSelectionType.ByValue)
                li = drp.Items.FindByValue(selectedValue.Trim());
            else
                li = drp.Items.FindByText(selectedValue.Trim());
            if (li != null)
                li.Selected = true;
        }}

    可以通过以下代码行调用此方法以按文本选择

    1
    DropDownList1.SelectItem("ABCD", Utilities.DropDownListSelectionType.ByText);

    或按值选择

    1
    DropDownList1.SelectItem("11", Utilities.DropDownListSelectionType.ByValue);

    如果上面的代码找不到传入的文本/值,则不会选择任何内容。


    获取URI的根域。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /// <summary>Gets the root domain of any URI</summary>
    /// <param name="uri">URI to get root domain of</param>
    /// <returns>Root domain with TLD</returns>
    public static string GetRootDomain(this System.Uri uri)
    {
        if (uri == null)
            return null;

        string Domain = uri.Host;
        while (System.Text.RegularExpressions.Regex.Matches(Domain, @"[\.]").Count > 1)
            Domain = Domain.Substring(Domain.IndexOf('.') + 1);
        Domain = Domain.Substring(0, Domain.IndexOf('.'));
        return Domain;
    }


    轻松地将对象序列化为XML:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public static string ToXml<T>(this T obj) where T : class
    {
        XmlSerializer s = new XmlSerializer(obj.GetType());
        using (StringWriter writer = new StringWriter())
        {
            s.Serialize(writer, obj);
            return writer.ToString();
        }
    }

    "<root><child>foo</child</root>".ToXml<MyCustomType>();