|
整理一下自己經(jīng)常用到的幾個(gè)擴(kuò)展方法,在實(shí)際項(xiàng)目中確實(shí)好用,節(jié)省了不少的工作量。 1 匿名對象轉(zhuǎn)化在WinForm中,如果涉及較長時(shí)間的操作,我們一般會(huì)用一個(gè)BackgroundWorker來做封裝長時(shí)間的操作,給它傳遞一個(gè)類型參數(shù)。 var parm = new { UserId = txtUserId.Text, UserText = txtText.Text, TabIndex = tabControl.SelectedIndex, CheckUrl = urls, SupportFormat = supportFormat, DeleteMHT = chkDelete.Checked, FileFormat=supportFileFormat }; backgroundWorker.RunWorkerAsync(parm); 注意到一點(diǎn),我這里沒有用一個(gè)類型,而是用一個(gè)匿名類型,以節(jié)省類型的定義。這種場景經(jīng)常遇到,比如這個(gè)后臺(tái)方法需要傳三個(gè)參數(shù),那個(gè)后臺(tái)方法需要五個(gè)參數(shù),如果不用我這個(gè)方法,那你需要額外的定義二個(gè)類型,分別包含三個(gè)參數(shù)或是五個(gè)參數(shù)。 再來看DoWork時(shí),如何使用這個(gè)匿名方法 private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
#region Download
backgroundWorker.ReportProgress(10, string.Format("Analyst beginning......"));
var parm = e.Argument.TolerantCast(new { UserId = string.Empty, UserText = string.Empty, TabIndex = 0, CheckUrl = new List<string>(), SupportFormat = string.Empty, DeleteMHT = false, FileFormat=string.Empty}); 與RunWorkerAsnyc中傳遞的參數(shù)一樣,定義一個(gè)匿名類型,各屬性放默認(rèn)值,然后調(diào)用TolerantCast方法,即可得到前面?zhèn)魅氲闹怠?/p> 這個(gè)方法很大的方便了這種使用情景:方法與方法之間需要傳遞不固定的參數(shù),但是又不愿意重新定義一個(gè)新的類型。這個(gè)方法不來自于CodeProject,我把它的代碼轉(zhuǎn)在下面,供您參考 /// <summary>
/// 轉(zhuǎn)換匿名類型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="o"></param>
/// <param name="example"></param>
/// <returns></returns>
public static T TolerantCast<T>(this object o, T example)
where T : class
{
IComparer<string> comparer = StringComparer.CurrentCultureIgnoreCase;
//Get constructor with lowest number of parameters and its parameters
var constructor = typeof (T).GetConstructors(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
).OrderBy(c => c.GetParameters().Length).First();
var parameters = constructor.GetParameters();
//Get properties of input object
var sourceProperties = new List<PropertyInfo>(o.GetType().GetProperties());
if (parameters.Length > 0)
{
var values = new object[parameters.Length];
for (int i = 0; i < values.Length; i )
{
Type t = parameters[i].ParameterType;
//See if the current parameter is found as a property in the input object
var source = sourceProperties.Find(delegate(PropertyInfo item)
{
return comparer.Compare(item.Name, parameters[i].Name) == 0;
});
//See if the property is found, is readable, and is not indexed
if (source != null && source.CanRead &&
source.GetIndexParameters().Length == 0)
{
//See if the types match.
if (source.PropertyType == t)
{
//Get the value from the property in the input object and save it for use
//in the constructor call.
values[i] = source.GetValue(o, null);
continue;
}
else
{
//See if the property value from the input object can be converted to
//the parameter type
try
{
values[i] = Convert.ChangeType(source.GetValue(o, null), t);
continue;
}
catch
{
//Impossible. Forget it then.
}
}
}
//If something went wrong (i.e. property not found, or property isn't
//converted/copied), get a default value.
values[i] = t.IsValueType ? Activator.CreateInstance(t) : null;
}
//Call the constructor with the collected values and return it.
return (T) constructor.Invoke(values);
}
//Call the constructor without parameters and return the it.
return (T) constructor.Invoke(null);
}2 集合對象上的擴(kuò)展方法先看例子,下面的測試方法 var @enum = new[] {1, 2, 3, 4}.AsEnumerable();
var sum = 0;
@enum.ForEach(n => sum = n);
這個(gè)擴(kuò)展方法,可以直接在一個(gè)集合上執(zhí)行一個(gè)Lambda表達(dá)式,返回結(jié)果,相當(dāng)于有二個(gè)參數(shù)的Fun<T,T>,來看它的源代碼定義 public static void ForEach<T>(this IEnumerable<T> @enum, Action<T> mapFunction)
{
foreach (var item in @enum) mapFunction(item);
}
3 字符串類型上的擴(kuò)展方法這里可以做的擴(kuò)展方法比較多,一個(gè)明顯的例子就是,依據(jù)String類型寫的Helper類型方法最多。 來看一個(gè)字符串拼湊的例子,平時(shí)我們用string.Format這樣的寫法,如果用下面的擴(kuò)展方法,看起來更直觀一些。 string s = "{0} ought to be enough for {1}.";
string param0 = "64K";
string param1 = "everybody";
string expected = "64K ought to be enough for everybody.";
Assert.AreEqual(expected, s.FormatWith(param0, param1),
這個(gè)擴(kuò)展方法的定義也簡單,只有一行代碼 /// <summary>
/// Formats a string with two literal placeholders.
/// </summary>
/// <param name="text">The extension text</param>
/// <param name="arg0">Argument 0</param>
/// <param name="arg1">Argument 1</param>
/// <returns>The formatted string</returns>
public static string FormatWith(this string text, object arg0, object arg1)
{
return string.Format(text, arg0, arg1);
}可以考慮把參數(shù)延長到任意個(gè),改寫這個(gè)擴(kuò)展方法,也只需要一行代碼皆可 /// <summary>
/// Formats a string with two literal placeholders.
/// </summary>
/// <param name="text">The extension text</param>
/// <param name="arg0">Argument 0</param>
/// <param name="arg1">Argument 1</param>
/// <returns>The formatted string</returns>
public static string FormatWith(this string text, params object[] args))
{
return string.Format(text, args);
}
另一個(gè)有用的擴(kuò)展方法是字符串與枚舉類型之間的轉(zhuǎn)化,擴(kuò)展方法定義如下 /// <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 ToEnum<T>(this string value)
{
return ToEnum<T>(value, false);
}
參考下面的例子,使用這個(gè)實(shí)用的擴(kuò)展方法 enum ProductVersion
{
Standard,
Enteprise,
Ultimate
}
[TestMethod]
public void StringToEnumTest()
{
Assert.AreEqual(ProductVersion.Standard, "Standard".ToEnum<ProductVersion>());
}
4 數(shù)字類型上的擴(kuò)展方法我這里有一個(gè)明顯的例子是顯示容量的擴(kuò)展方法,請看下面的方法組: /// <summary>
/// Kilobytes
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static int KB(this int value)
{
return value * 1024;
}
/// <summary>
/// Megabytes
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static int MB(this int value)
{
return value.KB() * 1024;
}
/// <summary>
/// Gigabytes
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static int GB(this int value)
{
return value.MB() * 1024;
}
/// <summary>
/// Terabytes
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static long TB(this int value)
{
return (long)value.GB() * (long)1024;
}
用起來就很輕松了,簡單的一行代碼,獲取容量的數(shù)字值 var kb = 1.KB(); var mb = 1.MB(); var gb = 1.GB(); var tb = 1.TB(); 最后一組擴(kuò)展方法在計(jì)算百分比中經(jīng)常遇到,比如統(tǒng)計(jì)計(jì)算,任務(wù)完成百分比計(jì)算: #region PercentageOf calculations
/// <summary>
/// The numbers percentage
/// </summary>
/// <param name="number">The number.</param>
/// <param name="percent">The percent.</param>
/// <returns>The result</returns>
public static decimal PercentageOf(this int number, int percent)
{
return (decimal)(number * percent / 100);
}
/// <summary>
/// Percentage of the number.
/// </summary>
/// <param name="percent">The percent</param>
/// <param name="number">The Number</param>
/// <returns>The result</returns>
public static decimal PercentOf(this int position, int total)
{
decimal result = 0;
if (position > 0 && total > 0)
result = (decimal)position / (decimal)total * 100;
return result;
}
public static decimal PercentOf(this int? position, int total)
{
if (position == null) return 0;
decimal result = 0;
if (position > 0 && total > 0)
result = (decimal)((decimal)position / (decimal)total * 100);
return result;
}
/// <summary>
/// The numbers percentage
/// </summary>
/// <param name="number">The number.</param>
/// <param name="percent">The percent.</param>
/// <returns>The result</returns>
public static decimal PercentageOf(this int number, float percent)
{
return (decimal)(number * percent / 100);
}
/// <summary>
/// Percentage of the number.
/// </summary>
/// <param name="percent">The percent</param>
/// <param name="number">The Number</param>
/// <returns>The result</returns>
public static decimal PercentOf(this int position, float total)
{
decimal result = 0;
if (position > 0 && total > 0)
result = (decimal)((decimal)position / (decimal)total * 100);
return result;
}
/// <summary>
/// The numbers percentage
/// </summary>
/// <param name="number">The number.</param>
/// <param name="percent">The percent.</param>
/// <returns>The result</returns>
public static decimal PercentageOf(this int number, double percent)
{
return (decimal)(number * percent / 100);
}
/// <summary>
/// Percentage of the number.
/// </summary>
/// <param name="percent">The percent</param>
/// <param name="number">The Number</param>
/// <returns>The result</returns>
public static decimal PercentOf(this int position, double total)
{
decimal result = 0;
if (position > 0 && total > 0)
result = (decimal)((decimal)position / (decimal)total * 100);
return result;
}
/// <summary>
/// The numbers percentage
/// </summary>
/// <param name="number">The number.</param>
/// <param name="percent">The percent.</param>
/// <returns>The result</returns>
public static decimal PercentageOf(this int number, decimal percent)
{
return (decimal)(number * percent / 100);
}
/// <summary>
/// Percentage of the number.
/// </summary>
/// <param name="percent">The percent</param>
/// <param name="number">The Number</param>
/// <returns>The result</returns>
public static decimal PercentOf(this int position, decimal total)
{
decimal result = 0;
if (position > 0 && total > 0)
result = (decimal)position / (decimal)total * 100;
return result;
}
/// <summary>
/// The numbers percentage
/// </summary>
/// <param name="number">The number.</param>
/// <param name="percent">The percent.</param>
/// <returns>The result</returns>
public static decimal PercentageOf(this int number, long percent)
{
return (decimal)(number * percent / 100);
}
/// <summary>
/// Percentage of the number.
/// </summary>
/// <param name="percent">The percent</param>
/// <param name="number">The Number</param>
/// <returns>The result</returns>
public static decimal PercentOf(this int position, long total)
{
decimal result = 0;
if (position > 0 && total > 0)
result = (decimal)position / (decimal)total * 100;
return result;
}
#endregion
來看幾個(gè)測試用例,增強(qiáng)對它的直觀感受,因?yàn)樯婕暗降臄?shù)值類型多一些,所以擴(kuò)展方法的數(shù)量也多。 Assert.AreEqual(33.0M, 100.PercentageOf(33)); Assert.AreEqual(33.0M, 33.PercentOf(100)); Assert.AreEqual(33.0M, 100.PercentageOf((float)33.0F)); Assert.AreEqual(33.0M, 33.PercentOf((float)100.0F)); Assert.AreEqual(33.0M, 100.PercentageOf((double)33.0F)); Assert.AreEqual(33.0M, 33.PercentOf((double)100.0F)); Assert.AreEqual(33.0M, 100.PercentageOf((decimal)33.0M)); Assert.AreEqual(33.0M, 33.PercentOf((decimal)100.0M)); Assert.AreEqual(33.0M, 100.PercentageOf((long)33)); Assert.AreEqual(33.0M, 33.PercentOf((long)100));
|
|
|