[英]How to cast an object of unknown type to its type in run time?
解決這個問題的類似線程可能在SO上,但我不理解它們:(
我有這樣的場景:
internal static void AddToListBox(ListBox lb, User usr)
{
if (CanAddUser(lb, usr))
lb.Items.Add(usr);
}
static bool CanAddUser(ListBox lb, User usr)
{
foreach (User u in lb.Items)
{
if (u.Id == usr.Id)
return false;
}
return true;
}
現在,我有另一個完全類似的場景,例如:
internal static void AddToList(List<User> lstUser, User usr)
{
if (CanAddUser(lstUser, usr))
lstUser.Add(usr);
}
static bool CanAddUser(List<User> lstUser, User usr)
{
foreach (User u in lstUser)
{
if (u.Id == usr.Id)
return false;
}
return true;
}
基本上兩個集合都做相同的事情。 我很好奇我是否可以使它成為一個函數,但這只是它的工作方式,這使代碼更加冗長:
internal static void AddToList(IEnumerable enumerable, User usr)
{
if (enumerable is ListBox.ObjectCollection)
{
if (CanAddUser(enumerable, usr))
((ListBox.ObjectCollection)enumerable).Add(usr);
}
else if (enumerable is List<User>)
{
if (CanAddUser(enumerable, usr))
((List<User>)enumerable).Add(usr);
}
}
internal static bool CanAddUser(IEnumerable enumerable, User usr)
{
foreach (User u in enumerable)
{
if (u.Id == usr.Id)
return false;
}
return true;
}
就像我說的那樣,它可以工作,但是if else塊使它看起來很難看,並且扼殺了縮短代碼的想法。 我可以做這樣的事情:
internal static void AddToList(IEnumerable enumerable, User usr)
{
if (CanAddUser(enumerable, usr))
((whatever the type is passed, just find it yourself)enumerable).Add(usr);
}
??
我試過了
internal static void AddToList(IEnumerable enumerable, User usr)
{
if (CanAddUser(enumerable, usr))
((enumerable.GetType()) / (typeof(enumerable))enumerable).Add(usr);
//both which wont compile.
}
那怎么去呢? 將IEnumerable
轉換為未知類型是不可能的? 還是解決方案太混亂,以至於我不打算放棄該計划? 如果我知道傳遞的IEnumerable
只有ListBox.ObjectCollection
類型和List<User>
而不是if else邏輯,那么可以做任何事情嗎? 很抱歉這篇冗長的文章,只需要解釋我的要求..
更新: StriplingWarrior的答案必然解決我的問題,但我想知道如果我要實現最后一個函數,對象是如何轉換為其原始類型的。 可能通過反思或其他東西。 我將解決方案標記為答案。 再次感謝@StriplingWarrior。
更新2:更清楚地說,忘記上面已發布的所有內容。 假設我有如下功能。 Admonish()
是我分別在類型List<Naughty>
和List<Obedient>
對象上定義的擴展方法。 我怎樣才能只編寫一個Sanitize
函數並將List<Naughty
或List<Obedient
傳遞給它? 像這樣:
internal static void Sanitize(IEnumerable enumerable)
{
enumerable.Admonish();
}
??
我知道我可以這樣做:
internal static void Sanitize(IEnumerable enumerable)
{
if (enumarable is List<Naughty>)
((List<Naughty>)enumerable).Admonish();
if (enumarable is List<Obedient>)
((List<Obedient>)enumerable).Admonish();
}
我將如何一口氣做到這一點,就像這樣:
internal static void Sanitize(IEnumerable enumerable)
{
((Determine type here, but how??)enumerable).Admonish();
}
希望問題很清楚。 我不是在尋找特殊情況的解決方案,而是在運行時獲取類型的通用解決方案, 以便可以將對象轉換為它的類型 !
由於ListBox.ObjectCollection
實現了IList
接口,因此您應該在兩種情況下都可以使用該接口。
internal static void AddToList(IList list, User usr)
{
if (!list.Cast<User>().Any(u => u.Id == user.Id))
list.Add(usr);
}
不適用於IEnumerable
的唯一原因是因為該接口沒有Add
方法。
這個問題比乍看起來要復雜得多,答案取決於您的告誡方法。 它只是迭代列表並在列表的每個成員上執行特定的操作嗎?
public static void Admonish(this IEnumerable<Naughty> followers)
{
foreach(var follower in followers) { follower.Preach(); }
}
public static void Admonish(this IEnumerable<Obedient> followers)
{
foreach(var follower in followers) { follower.Preach(); }
}
在這種情況下,您可以使Naughty和Obedient都實現一個特定的接口:
public interface IFollower
{
void Preach();
}
public class Naughty : IFollower {...}
public class Obedient : IFollower {...}
public static void Admonish(this IEnumerable<IFollower> followers)
{
foreach(var follower in followers) { follower.Preach(); }
}
internal static void Sanitize(IEnumerable enumerable)
{
enumerable.Cast<IFollower>().Admonish();
}
另一方面,如果Admonish根據您要查看的類型做一些不同的事情,那就不是那么簡單了:
public static void Admonish(this IEnumerable<Naughty> followers)
{
foreach(var follower in followers) { follower.Chastise(); }
}
public static void Admonish(this IEnumerable<Obedient> followers)
{
foreach(var follower in followers) { follower.Encourage(); }
}
在這種情況下,自動調用正確的Admonish方法的唯一方法是使用反射來查找和調用它。 就.NET框架而言,沒有理由相信這兩個Admonish
方法有任何關聯,所以你不能只假裝它們是相同的方法。
如果您願意使用非靜態方法制作Admonish,則可以使用dynamic
關鍵字來完成或多或少的嘗試,但它不適用於擴展方法:
public class Admonisher
{
public void Admonish(IEnumerable<Naughty> followers)
{
foreach(var follower in followers) { follower.Chastise(); }
}
public void Admonish(IEnumerable<Obedient> followers)
{
foreach(var follower in followers) { follower.Encourage(); }
}
}
internal static void Sanitize(dynamic enumerable)
{
dynamic admonisher = new Admonisher();
admonisher.Admonish(enumerable);
}
但即使這種方法只有在傳入的可枚舉由通用IEnumerable<Naughty>
或IEnumerable<Obedient>
支持時才有效。 如果你傳遞一個ListBox.ObjectCollection
,即使動態運行時框架也無法確定要調用哪個Admonish方法。
首先,讓我說反思通常不是解決此類問題的最佳解決方案。 反射很慢,並且抵消了已編譯編程語言的大多數優點。 但是如果你認為這是要走的路,那么你就是這樣做的。 假設您的Admonish
方法簽名如下所示:
public static void Admonish(this IEnumerable<Naughty> followers)
...並假設您有一個列表,其實際實現類型實現IEnumerable<Naughty>
:
IList list = new List<Naughty>(); // List<Naughty> implements IEnumerable<Naughty>
...你可以找到並調用這樣的方法:
var utilClass = typeof(Utility); // the class with your admonish methods
var admonishMethod =
(from m in utilClass.GetMethods()
where m.IsStatic && m.Name == "Admonish"
let parameter = m.GetParameters()[0]
where parameter.ParameterType.IsAssignableFrom(list.GetType())
select m).Single();
admonishMethod.Invoke(null, new[]{list});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.