让我们把你的优秀和最喜欢的扩展方法列一个列表。
要求是必须发布完整的代码,以及如何使用它的示例和解释。
基于对这个主题的高度兴趣,我在Codeplex上建立了一个名为extensionoverflow的开源项目。
请将您的回答标记为接受,以便将代码放入Codeplex项目。
请张贴完整的源代码,而不是一个链接。
Codeplex上新闻:
24.08.2010 Codeplex页面现在在这里:http://extensionoverflow.codeplex.com/
11.11.2008 XmlSerialize / XmlDeserialize现在是实现和单元测试。
11.11.2008仍有发展空间。;-)现在就加入!
11.11.2008第三位贡献者加入了ExtensionOverflow,欢迎加入BKristensen
11.11.2008 FormatWith现在是实现和单元测试。
09.11.2008第二个贡献者加入ExtensionOverflow。欢迎来到chakrit。
我们需要更多的开发人员。: -)
09.11.2008 ThrowIfArgumentIsNull现已在Codeplex上实现和单元测试。
这些扩展方法异步调用事件。他们受到了StackOverflow的启发。
/// <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);
}
}
使用方法:
public class Foo
{
public event EventHandler<EventArgs> Bar;
public void OnBar()
{
Bar.InvokeAsync(this, EventArgs.Empty);
}
}
请注意,在调用事件之前,您不必检查事件是否为空。例如:
EventHandler<EventArgs> handler = Bar;
if (handler != null)
{
// Invoke the event
}
测试:
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");
}
调用事件将(通常)产生以下输出:
开始执行重要的事情
处理3
处理2
处理1
完成重要的任务
如果事件是同步调用的,它总是会产生这样的输出-并延迟“重要”内容的执行:
处理1
处理2
处理3
开始执行重要的事情
完成重要的任务
您可能已经知道扩展方法的一个有趣用法是作为一种mixin。一些扩展方法,比如XmlSerializable,几乎污染了所有类;这对大多数人来说没有意义,比如Thread和SqlConnection。
一些功能应该显式地混合到希望拥有它的类中。我对这种类型提出了一种新的表示法,以M为前缀。
XmlSerializable是这样的:
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));
}
}
然后一个类将其混合:
public class Customer : MXmlSerializable {
public string Name { get; set; }
public bool Preferred { get; set; }
}
用法很简单:
var customer = new Customer {
Name = "Guybrush Threepwood",
Preferred = true };
var xml = customer.ToXml();
如果您喜欢这个想法,您可以在项目中为有用的mixin创建一个新的名称空间。你怎么看?
哦,顺便说一下,我认为大多数扩展方法都应该显式地测试null。
灵感来自弦。IsNullOrEmpty
要验证给定的List为空或空
public static bool IsNullOrEmpty<TSource>(this List<TSource> src)
{
return (src == null || src.Count == 0);
}
这个是验证给定的两个文件和属性
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;
}
像这样使用它
FileInfo fo = new FileInfo("c:\\netlog.txt");
FileInfo f1 = new FileInfo("c:\\regkey.txt");
fo.compare(f1, "CreationTime");
一些DataSet/DataRow扩展,使使用db结果更简单
只需在DataRow上使用. field ("fieldname"),如果可以,它将强制转换它,可选的默认值可以包括在内。
还有DataSet上的. hasrows(),这样你就不需要检查表和行的存在。
例子:
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");
}
}
}
代码:
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);
}
}
字符串。格式的快捷方式:
public static class StringExtensions
{
// Enable quick and more natural string.Format calls
public static string F(this string s, params object[] args)
{
return string.Format(s, args);
}
}
例子:
var s = "The co-ordinate is ({0}, {1})".F(point.X, point.Y);
要快速复制粘贴,请点击这里。
难道你不觉得输入“一些字符串”. f(“param”)而不是字符串更自然吗?格式(“一些字符串”,“参数”)?
想要一个更容易读懂的名字,试试下面的建议:
s = "Hello {0} world {1}!".Fmt("Stack", "Overflow");
s = "Hello {0} world {1}!".FormatBy("Stack", "Overflow");
s = "Hello {0} world {1}!".FormatWith("Stack", "Overflow");
s = "Hello {0} world {1}!".Display("Stack", "Overflow");
s = "Hello {0} world {1}!".With("Stack", "Overflow");
..