下面的代码循环遍历字符串字典, IMyCompanySettings 查找实现 IMyCompanyProductSetting 的值。很明显,尝试投射和提出异常是一种非常昂贵的方法。
public static List<IMyCompanyProductSetting> GetProductSettings(ConfigurationManager cfm)
{
List<IMyCompanyProductSetting> ret = new List<IMyCompanyProductSetting>();
foreach(IMyCompanySetting setting in cfm.Values)
{
try
{
IMyCompanyProductSetting prod = (IMyCompanyProductSetting)setting;
ret.Add(prod);
}
catch
{
// Do nothing.
}
}
return ret;
}
有什么更好的方法可以做到这一点?
答案 0 :(得分:14)
使用[object] is [interface/class]
表达式:
if (setting is IMyCompanyProductSetting) {
...
}
或者,您可以使用试图转换对象的as
关键字,如果失败,它将返回null
而不是抛出异常。请注意,目标类型必须是as
关键字中的引用类型:
var prod = setting as IMyCompanyProductSetting;
if (prod != null) {
...
}
您应始终使用上述代码而不是等效的异常处理。
IEnumerable
(LINQy):正如Jon Skeet指出的那样,你应该使用OfType
扩展方法轻松过滤序列(假设你得到了LINQ):
var filteredSequence = sequence.OfType<TargetType>();
IEnumerable
转换为类型(LINQy):如果您想尝试将每个元素转换为目标类型(而不是按类型过滤),则可以使用Cast
扩展方法:
var castedSequence = sequence.Cast<TargetType>();
答案 1 :(得分:7)
“硬”方式(LINQ之前)是使用“as”。这比使用“is”然后每次转换(因为“是”和转换需要执行时间检查)更有效:
IMyCompanyProductSetting prod = setting as IMyCompanyProductSetting;
if (prod != null)
{
ret.Add(prod);
}
有关何时使用“as”以及何时使用演员表,请参阅another question。
但是,如果您使用的是.NET 3.5,则非常简单:
return cfm.Values.OfType<IMyCompanyProductSetting>().ToList();
非常简单:)
答案 2 :(得分:2)
Mehrdad有答案。我只会补充一点,你永远不应该使用“尝试/捕捉一切”技巧。在这种情况下,最好是尝试捕获InvalidCastException。您不希望忽略其他一些异常,可能来自您尝试调用的方法的执行。
答案 3 :(得分:1)
您应该使用'Is'语句来获得更简洁,更不容易出错的代码。请参阅下面的示例。
if (setting Is IMyCompanyProductSetting)
ret.add((IMyCompanyProductSetting)setting);
答案 4 :(得分:1)
要么
if (setting is IMyCompanyProductSetting)
{
IMyCompanyProductSetting prod = (IMyCompanyProductSetting)setting;
}
或
IMyCompanyProductSetting prod = setting as IMyCompanyProductSetting;
if (setting != null)
{
}