我想为泛型类创建一个包装函数,如下所示:
public class ColumnData
{
public static ColumnData<T> Create<T>(string name, int width, ColumnType type,
Func<T, string> dataFormater)
{
return new ColumnData<T>(name, width, type, dataFormater);
}
}
Create
方法将作为具有签名的另一个函数的参数调用:
public void populateFromData<TDATA>(IEnumerable<TDATA> data,
params ColumnData<TDATA>[] columns)
{
...
}
这里的目的是能够做到:
var myData = new List<MyDataType>();
dataListView.populateFromData(
myData,
ColumnData.Create("ID", 40, ColumnType.Numeric, x => x.ID.ToString());
但是,Create
无法根据预期的签名推断出自己的正确类型,因此lambda也不知道自己。
这是类型推断的限制,还是有办法使这个设置有效?
注意:如果需要,我愿意在此函数调用的某处指定实际数据类型,但我不想要为每个.Create()
指定它的
答案 0 :(得分:1)
有时您只需明确指定泛型类型参数,当c#无法推断它的实际类型时。
dataListView.populateFromData(
myData,
ColumnData.Create<MyDataType>("ID", 40, ColumnType.Numeric, x => x.ID.ToString());
答案 1 :(得分:1)
正如其他人所解释的那样,使用您想要的确切语法是不可能的。作为解决方法,您可以将键入内容移动到单独的构建类:
public class ColumnDataBuilder
{
public static ColumnDataBuilder<T> ColumnsFor<T>(IEnumerable<T> data)
{
return new ColumnDataBuilder<T>(data);
}
}
public class ColumnDataBuilder<T> : ColumnDataBuilder
{
public IEnumerable<T> Data { get; private set; }
public ColumnDataBuilder(IEnumerable<T> data)
{
this.Data = data;
}
public ColumnData<T> Create(string name, int width, ColumnType type, Func<T, string> dataFormater)
{
return new ColumnData<T>(name, width, type, dataFormater);
}
public void populateFromData(params ColumnData<T>[] columns)
{
///...
}
}
public class ColumnData<T>
{
public ColumnData(string name, int width, ColumnType type, Func<T, string> dataFormatter)
{
}
}
然后用法可能如下:
var builder = ColumnDataBuilder.ColumnsFor(new List<MyDataType>());
builder.populateFromData(builder.Create("ID", 40, ColumnType.Numeric, x => x.ID.ToString()));
IEnumerable<MyDataType> data = builder.Data;
或者更接近您的示例用法(如果您希望populateFromData
保留dataListView
),在这种情况下您可以放弃ColumnDataBuilder<T>.populateFromData
方法(因为您的评论似乎不是可以留在那里):
var myData = new List<MyDataType>();
var builder = ColumnDataBuilder.ColumnsFor(myData);
dataListView.populateFromData(myData, builder.Create("ID", 40, ColumnType.Numeric, x => x.ID.ToString()));
或者两全其美:
var builder = ColumnDataBuilder.ColumnsFor(new List<MyDataType>());
dataListView.populateFromData(builder.Data, builder.Create("ID", 40, ColumnType.Numeric, x => x.ID.ToString()));
编辑:考虑到您的评论,您可能不希望populateFromData
或甚至可能IEnumerable<T> Data
存储在ColumnDataBuilder
上,因此您可以简化这样做:
public class ColumnDataBuilder<T> : ColumnDataBuilder
{
public ColumnData<T> Create(string name, int width, ColumnType type, Func<T, string> dataFormater)
{
return new ColumnData<T>(name, width, type, dataFormater);
}
}
public class ColumnDataBuilder
{
public static ColumnDataBuilder<T> ColumnsFor<T>(IEnumerable<T> data)
{
return new ColumnDataBuilder<T>();
}
}
使用上面的用法:
var myData = new List<MyDataType>();
var builder = ColumnDataBuilder.ColumnsFor(myData);
dataListView.populateFromData(myData, builder.Create("ID", 40, ColumnType.Numeric, x => x.ID.ToString()));
答案 2 :(得分:0)
我刚提出的一个答案涉及别名。我删除了包装类并将Create
方法直接移到ColumnData<T>
类中,然后添加:
using ColumnData = ColumnData<MyDataType>;
这允许我使用类型提示访问编译器ColumnData.Create()
,而无需在每行上指定它。我需要在每个我想要使用它的文件中创建别名,但这是一个可行的解决方案。