[英]How can I create a List(of T) where T is an interface of (T) and the contents of the List inherit an Abstract class that implements the interface of T
我正在尝试实现一些通用配置类型,但遇到了转换问题。 理想情况下,我想要的是一个强类型的配置值实例,可以分配给我们不同的导出器。
我所拥有的是:
IConfigurableExport
:将导出器标记为可配置的接口,并包含ICollection<IExportConfiguration<Object>> Configurations
属性IExportConfiguration<T>
:定义通用属性(名称、描述等)的接口ExportConfiguration<T>
:实现IExportConfiguration<T>
抽象类,将接口属性设置为 Abstract,添加一些常用功能,例如从配置值列表中设置自身的值等等ConfigurationInstance<bool>
:继承ExporterConfiguration<Boolean>
用于配置导出器的 UI 是基于 IConfigurableExport.Configurations 中的值动态构建的。 当我尝试调用 IConfigurableExport.Configurations 时,出现转换错误。 下面是一些示例代码来说明问题:
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var t = new MyExporter();
var configs = t.Configurations;
foreach(var conf in configs){
Console.WriteLine(conf.Name);
}
}
}
public interface IExportConfiguration<T>{
string Description {get;}
Guid Id {get;}
string Name {get;}
T Value {get; set;}
}
public abstract class ExportConfiguration<T>
: IExportConfiguration<T>
{
public abstract string Description { get; }
public abstract string Name { get; }
public abstract Guid Id { get; }
public abstract T Value { get; set; }
public abstract T DefaultValue { get; set; }
public virtual void SetValue(ICollection<KeyValuePair<Guid, object>> values)
{
if (values.Any(kvp => kvp.Key == this.Id))
Value = (T)values.First(kvp => kvp.Key == this.Id).Value;
else
Value = this.DefaultValue == null ? this.DefaultValue : default(T);
}
}
public interface IConfigurableExport {
ICollection<IExportConfiguration<object>> Configurations {get;}
}
public class MyConfig : ExportConfiguration<bool> {
public override string Description { get { return "This is my description"; }}
public override string Name { get{ return "My Config Name"; }}
public override Guid Id { get { return Guid.Parse("b6a9b81d-412d-4aa8-9090-37c9deb1a9f4"); }}
public override bool Value { get; set;}
public override bool DefaultValue { get; set;}
}
public class MyExporter : IConfigurableExport {
MyConfig conf = new MyConfig();
public ICollection<IExportConfiguration<object>> Configurations {
get {
return new List<IExportConfiguration<object>> { (IExportConfiguration<object>)conf };
}
}
}
这是一个 dontnetfiddle来说明这个问题
主要问题是IExportConfiguration<T>
定义了一个T Value {get; set;}
T Value {get; set;}
如果您有IExportConfiguration<bool>
,则不能将IExportConfiguration<bool>
IExportConfiguration<object>
转换为IExportConfiguration<object>
因为您无法使用object
类型设置Value
,必须使用bool
类型设置它才能它是类型安全的。
为了能够进行这种类型的转换,您需要使用如下所示的协变接口
public interface IExportConfiguration<T> : IReadOnlyExportConfiguration<T>{
new T Value {get; set;}
}
//this interface is covariant, and if you have a IReadOnlyExportConfiguration<string>
//it can be cast to an IReadOnlyExportConfiguration<object>
public interface IReadOnlyExportConfiguration<out T>{
string Description {get;}
Guid Id {get;}
string Name {get;}
T Value {get;}
}
然后您可以将您的可配置导出重新定义为
public interface IConfigurableExport {
ICollection<IReadOnlyExportConfiguration<object>> Configurations {get;}
}
但是你不能使用MyConfig
作为 bool 配置,因为IReadOnlyExportConfiguration<bool>
不会转换为IReadOnlyExportConfiguration<object>
因为 bool 是一种简单的数据类型。 T 的类型必须是类类型才能与object
协变。
public class MyConfig : ExportConfiguration<string> {
public override string Description { get { return "This is my description"; }}
public override string Name { get{ return "My Config Name"; }}
public override Guid Id { get { return Guid.Parse("b6a9b81d-412d-4aa8-9090-37c9deb1a9f4"); }}
public override string Value { get; set;}
public override string DefaultValue { get; set;}
}
然后最后你的出口商变成
public class MyExporter : IConfigurableExport {
MyConfig conf = new MyConfig();
public ICollection<IReadOnlyExportConfiguration<object>> Configurations {
get {
return new List<IReadOnlyExportConfiguration<object>> { (IReadOnlyExportConfiguration<object>)conf };
}
}
}
但此时您将无法为您的配置设置值,如果需要,您将需要重新构建您的解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.