我有一个 List<object>各种类型的对象的集合.
我正在编写一个辅助方法,它将返回一个特定类型的对象.辅助方法将接受类型名称作为字符串参数.
注意:我使用的是3.5框架.
如果需要使用字符串作为参数,则不能依赖OfType<T>()扩展方法.幸运的是,它很容易模仿:
public IEnumerable<object> OfType(this List<object> list, string typeName)
{
return list.Where(x => x != null && x.GetType().Name == typeName);
}
Run Code Online (Sandbox Code Playgroud)
正如@ChrisSinclair在评论中所指出的,该解决方案不管理转换,强制转换和继承/接口.转换(因为用户定义的转换运算符)和转换(因为TypeConverters和IConvertible接口)有点棘手.对于简单(隐式)强制转换(如继承和接口),您可以使用:
public IEnumerable<object> OfType(this List<object> list, string typeName)
{
Type type = Type.GetType(typeName);
return list.Where(x => x != null && type.IsAssignableFrom(x.GetType()));
}
Run Code Online (Sandbox Code Playgroud)
如何在运行时执行转换(即使使用CUSTOM CONVERSION OPERATORS)
我发现我需要的东西就像我在这个答案中发布的代码一样,但我不得不扩展它一点,这里是一个更好的实现,它负责自定义转换和转换.
将所有内容放在一个CastExtensions类中(如果不这样做,则更新代码)然后enum将其声明为小选项:
[Flags]
public enum CastOptions
{
None = 0,
ExcludeNulls = 1,
UseConversions = 2
}
Run Code Online (Sandbox Code Playgroud)
该问题是,C#,一般是静态类型语言,这意味着几乎所有(关于类型)必须在编译时是已知的(然后执行,你必须知道键入要投射到在编译时投).此函数处理简单情况(如派生)和更复杂的情况(接口,自定义转换运算符 - 强制转换 - 和转换 - 在需要时).
public static IEnumerable<object> OfType(this List<object> list,
string typeName, CastOptions options)
{
Type type = Type.GetType(typeName);
foreach (var obj in list)
{
if (Object.ReferenceEquals(obj, null))
{
if (options.HasFlag(CastOptions.ExcludeNulls))
continue;
yield return obj;
}
var objectType = obj.GetType();
// Derived type?
if (type.IsAssignableFrom(objectType))
yield return obj;
// Should we try to convert?
if (!options.HasFlag(CastOptions.UseConversions))
continue;
// Castable?
object convertedValue = null;
try
{
var method = typeof(CastExtensions)
.GetMethod("Cast", BindingFlags.Static|BindingFlags.NonPublic)
.MakeGenericMethod(type);
convertedValue = method.Invoke(null, new object[] { obj });
}
catch (InvalidCastException)
{
// No implicit/explicit conversion operators
}
if (convertedValue != null)
yield return convertedValue;
// Convertible?
if (options.HasFlag(CastOptions.UseConversions))
{
try
{
IConvertible convertible = obj as IConvertible;
if (convertible != null)
convertible.ToType(type, CultureInfo.CurrentCulture);
}
catch (Exception)
{
// Exact exception depends on the source object type
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,转换可能与转换等效或不等效,实际上它取决于实现以及操作中涉及的确切类型(这就是您可以通过选项启用或禁用此功能的原因).
这是在运行时转换所需的小辅助函数:
private static T Cast<T>(object obj)
{
return (T)obj;
}
Run Code Online (Sandbox Code Playgroud)
我们可以在运行时发出这个代码(我想甚至使用表达式,但我没有尝试)但是一个小的帮助器方法将生成我们需要的代码(从一个对象转换为一个在运行时类型已知的通用).请注意,此投如预期的值类型功能不起作用,例如:
int a = 1;
float a = Cast<float>(a); // Run-time error
Run Code Online (Sandbox Code Playgroud)
这是因为(object)1无法将其转换为其他任何内容int(对于所有盒装值类型都是如此).如果您使用的是C#4.0,则应将object参数更改为obj,dynamic并且所有内容都将按预期工作(适用于所有类型).