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);