gpt4 book ai didi

c# - 对 Func 选择器属性使用逆变

转载 作者:太空宇宙 更新时间:2023-11-03 16:06:46 25 4
gpt4 key购买 nike

我正在设计一个通用的列定义类,它将充当实体属性的选择器,所有这些都是为了更容易管理 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 in 参数通用,out 将始终是一个对象。

如何实现这种场景,是否需要实现自定义 Func 或者 dotnet 是否已经有适合这种目的的类型?

目前我能看到的唯一解决方案是创建具有 Func< object, object > Selector 属性的非泛型 DisplayColumn 类,并在每个赋值中将参数转换为具体类型,这显然不是一个很好的解决方案。另一种选择是继承基类非泛型 DisplayColumn 类并将泛型选择器放在继承的泛型类中,但是在呈现数据时使用此表达式需要调用继承的泛型类中的泛型方法,这对于性能和代码质量标准来说确实是 Not Acceptable 。

最佳答案

如果您也使 ColumnSet 成为通用的,那么您可以指定用于它返回的可枚举列的类型。下面的代码将编译,我想实现你所追求的。

    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<T>
{
public Type TypeHandled { get; set; }
public IEnumerable<IDisplayColumn<T>> Columns { get; set; }
}

public static class ColumnSetTest
{
static ColumnSetTest()
{
IDisplayColumn<SettingsContext> testSingleColumn = new DisplayColumn<SettingsContext> { Title = "Test", Selector = x => x.Values };


var columnSets = new List<ColumnSet<SettingsContext>>
{
new ColumnSet<SettingsContext>
{
TypeHandled = typeof(SettingsContext),
Columns = new List<IDisplayColumn<SettingsContext>>
{
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 }
}
}
};

}

关于c# - 对 Func<T, object> 选择器属性使用逆变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19090297/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com