是否有办法缩短以下方法(在扩展枚举方面更安全)?
private object MakeTypedList(IReadOnlyList<IData> readOnlyList, DataTypes dataTypes)
{
switch (dataTypes)
{
case DataTypes.Byte:
return readOnlyList
.Cast<IByteData>();
case DataTypes.Integer:
return readOnlyList
.Cast<IIntegerData>();
case DataTypes.Float:
return readOnlyList
.Cast<IFloatData>();
case DataTypes.Boolean:
return readOnlyList
.Cast<IBooleanData>();
case DataTypes.String:
return readOnlyList
.Cast<IStringData>();
case DataTypes.ByteArray:
return readOnlyList
.Cast<IByteArray>();
case DataTypes.IntegerArray:
return readOnlyList
.Cast<IIntegerArray>();
case DataTypes.FloatArray:
return readOnlyList
.Cast<IFloatArray>();
case DataTypes.BooleanArray:
return readOnlyList
.Cast<IBooleanArray>();
case DataTypes.StringArray:
return readOnlyList
.Cast<IStringArray>();
case DataTypes.List:
return readOnlyList
.Cast<IListData>();
case DataTypes.Image24:
return readOnlyList
.Cast<IImage24>();
case DataTypes.Image8:
return readOnlyList
.Cast<IImage8>();
case DataTypes.FloatSignal:
return readOnlyList
.Cast<IFloatSignal>();
case DataTypes.IntegerSignal:
return readOnlyList
.Cast<IIntegerSignal>();
case DataTypes.Record:
return readOnlyList
.Cast<IRecord>();
case DataTypes.Raw:
return readOnlyList
.Cast<IRaw>();
default:
throw new InvalidEnumArgumentException("Unsupported DataType!");
}
}
注意:标题必须保持不变,因为这些是我可以为此方法提供的数据。这是许多复杂架构的结果,无法更改。但是,我可以操作 - 例如 - 枚举本身或接口(例如添加属性等)。
提出同一问题的另一种方式。如果我有一个包含代表List<Base>
类型的对象的List<Derived>
变量,是否可以将Type
投射到Derived
?
List<Base> b;
Type t = typeof(Derived)
object derivedList = // use t only to construct List<Derived>
答案 0 :(得分:0)
反思非常难看,这肯定不比你已经写过的更短或更高效,但它会使它更具可扩展性。
首先,定义一个属性:
[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;
}
参见 - 丑陋。
请注意,我使用的是OfType
而不是Cast
。这会将列表过滤为所需类型,而不是在遇到不属于所请求类型的项目时抛出异常。如果您确实希望抛出异常,只需将"OfType"
更改回"Cast"
。
另请注意,为此,所有数据类型接口必须与IData
接口位于同一个程序集中。
关于您提供的第二个示例,您可以编写类似的扩展方法:
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);