我正在设计一个通用列定义类,它将充当实体属性的选择器,所有这些都是为了更容易管理 LOB 应用程序中不同方面的网格表示。
不幸的是,我试图在将包含在集合中的类中使用泛型参数时碰壁了。下面 SettingsContext 类的示例实现解释了正在发生的事情:
public interface IDisplayColumn<in T>
{
string Title { get; set; }
int Order { get; set; }
Func<T, object> Selector { get; }
}
public class DisplayColumn<T>: IDisplayColumn<T>
{
public string Title { get; set; }
public int Order { get; set; }
public Func<T, object> Selector { get; set; }
}
public class ColumnSet
{
public Type TypeHandled { get; set; }
public IEnumerable<IDisplayColumn<object>> Columns { get; set; }
}
public static class ColumnSetTest
{
static ColumnSetTest()
{
// Cannot implicitly convert type 'DisplayColumn<System.Configuration.SettingsContext>' to 'IDisplayColumn<object>'.
// An explicit conversion exists (are you missing a cast?)
IDisplayColumn<object> testSingleColumn = new DisplayColumn<SettingsContext> {Title = "Test", Selector = x => x.Values };
// another test with other type used as a source which should be assignable to DisplayColumn<object>
testSingleColumn = new DisplayColumn<SettingsProvider> { Title="Another test", Selector = x => x.ApplicationName };
// Cannot implicitly convert type 'System.Collections.Generic.List<IDisplayColumn<System.Configuration.SettingsContext>>'
// to 'System.Collections.Generic.IEnumerable<IDisplayColumn<object>>'.
// An explicit conversion exists (are you missing a cast?)
var columnSets = new List<ColumnSet>
{
new ColumnSet
{
TypeHandled = typeof(SettingsContext),
Columns = new List<IDisplayColumn<SettingsContext /* or object */>>
{
new DisplayColumn<SettingsContext> {Title = "Column 1", Order = 1, Selector = x => x.IsReadOnly },
new DisplayColumn<SettingsContext> {Title = "Column 2", Order = 2, Selector = x => x.IsSynchronized },
new DisplayColumn<SettingsContext> {Title = "Column 3", Order = 3, Selector = x => x.Keys }
}
}
};
}
}
我如何理解协方差和逆变的目的,这确实是预期的- out 参数应该用于 IDisplayColumn testSingleColumn = new DisplayColumn 分配,但我需要使参数中的 Func 通用,out 将始终是一个对象。
如何实现这样的场景,是否需要实现自定义 Func 或者 dotnet 已经有适合这种目的的类型?
目前我能看到的唯一解决方案是使用 Func< object, object > Selector 属性创建非泛型 DisplayColumn 类,并将参数转换为每个分配中的具体类型,这显然不是一个很好的解决方案。另一种选择是继承基本的非泛型 DisplayColumn 类并将泛型选择器放在继承的泛型类中,但是在呈现数据时使用此表达式将需要在继承的泛型类中调用泛型方法,这对于性能和代码质量标准来说确实是不可接受的。