C# 使用反射在两个通用列表之间进行转换
有没有办法使下面的方法更短(在扩展枚举方面更安全)C# 使用反射在两个通用列表之间进行转换,c#,type-conversion,C#,Type Conversion,有没有办法使下面的方法更短(在扩展枚举方面更安全) 反射非常难看,这当然不会比您已经编写的内容更短或更高性能,但它将使其更具可扩展性 首先,定义一个属性: [AttributeUsage(AttributeTargets.Interface)] public class DataTypeAttribute : Attribute { public DataTypeAttribute(DataTypes dataType) { DataType = dataType
反射非常难看,这当然不会比您已经编写的内容更短或更高性能,但它将使其更具可扩展性 首先,定义一个属性:
[AttributeUsage(AttributeTargets.Interface)]
public class DataTypeAttribute : Attribute
{
public DataTypeAttribute(DataTypes dataType)
{
DataType = dataType;
}
public DataTypes DataType { get; private set; }
}
然后用它标记您的接口:
[DataType(DataTypes.Byte)]
public interface IByteData : IData
{
}
[DataType(DataTypes.Integer)]
public interface IIntegerData : IData
{
}
// etc...
请注意,我假设您的所有数据类型都继承自IData
类型。(如果不是,他们可能应该这样做。)
现在,您可以实现MakeTypedList
方法,如下所示:
private object MakeTypedList(IReadOnlyList<IData> readOnlyList, DataTypes dataTypes)
{
var type = typeof(IData).Assembly.GetTypes()
.Where(t => t.IsInterface && typeof (IData).IsAssignableFrom(t))
.FirstOrDefault(t =>
{
var attribute = t.GetCustomAttributes(typeof(DataTypeAttribute), false)
.FirstOrDefault() as DataTypeAttribute;
return attribute != null && attribute.DataType == dataTypes;
});
if (type == null)
throw new InvalidEnumArgumentException("Unsupported DataType!");
var enumerable = typeof(Enumerable)
.GetMethod("OfType", BindingFlags.Static | BindingFlags.Public)
.MakeGenericMethod(type)
.Invoke(null, new object[] {readOnlyList});
// you can omit this last step if you just want an IEnumerable<T>
var list = typeof(Enumerable)
.GetMethod("ToList", BindingFlags.Static | BindingFlags.Public)
.MakeGenericMethod(type)
.Invoke(null, new object[] { enumerable });
return list;
}
这使得使用您提供的变量变得简单,如下所示:
List<Base> b;
Type t = typeof(Derived);
object derivedList = b.Cast(t);
列表b;
类型t=类型(派生);
对象派生列表=b.Cast(t);
注意,MakeTypedList
不返回键入的列表,它返回键入的IEnumerable。@ScottChamberlain是的,但可以。它也可以是IEnumerable。您可以在枚举中使用或其他类似属性来保存类型的全名,然后可以使用反射来使用该属性,然后使用反射来调用相应的强制转换方法。这只是一个想法,不是一个完整的实现,所以作为评论发布。如果你自己写的话,请随意回答你自己的问题并接受它。我可以使用第二个版本,因为我可以做相反的事情:我可以用适当的typeof()
标记DataTypes
,而不是用DataTypes
标记接口,从而快速接收所需的类型。在我的API中,这些是非常密切相关的,所以我可以简单地使用这个解决方案。的确,反思是相当丑陋的,但你的解决方案肯定会比我目前的解决方案灵活得多。谢谢
private object MakeTypedList(IReadOnlyList<IData> readOnlyList, DataTypes dataTypes)
{
var type = typeof(IData).Assembly.GetTypes()
.Where(t => t.IsInterface && typeof (IData).IsAssignableFrom(t))
.FirstOrDefault(t =>
{
var attribute = t.GetCustomAttributes(typeof(DataTypeAttribute), false)
.FirstOrDefault() as DataTypeAttribute;
return attribute != null && attribute.DataType == dataTypes;
});
if (type == null)
throw new InvalidEnumArgumentException("Unsupported DataType!");
var enumerable = typeof(Enumerable)
.GetMethod("OfType", BindingFlags.Static | BindingFlags.Public)
.MakeGenericMethod(type)
.Invoke(null, new object[] {readOnlyList});
// you can omit this last step if you just want an IEnumerable<T>
var list = typeof(Enumerable)
.GetMethod("ToList", BindingFlags.Static | BindingFlags.Public)
.MakeGenericMethod(type)
.Invoke(null, new object[] { enumerable });
return list;
}
public static object Cast<TBase>(this IEnumerable<TBase> original, Type type)
{
return typeof(Enumerable)
.GetMethod("Cast", BindingFlags.Static | BindingFlags.Public)
.MakeGenericMethod(type)
.Invoke(null, new object[] { original });
}
List<Base> b;
Type t = typeof(Derived);
object derivedList = b.Cast(t);