我有一个名为PointValue
,PointValue
的类,他的继承者只能通过接收一个float参数的参数化构造函数创建。
我有一个表示点列表的泛型类,模板类型必须从PointValue
继承。
我需要其中一个函数能够将点添加到列表中,因为我无法使用参数化构造函数来强制执行模板。我的函数获得pointValueCreator
来创建新点。
public class PointList<PointValueT> where PointValueT : PointValue
{
public void addPointToList(float f, Func<float,PointValueT> pointValueCreator)
{
// do something to f and then add a new point:
mylist.Add(pointValueCreator(f));
}
}
所以现在如果我有这样的事情:
PointList<PointValue> bla = new PointList<PointValue>();
我可以这样调用我的函数:
bla.addPointToList(f, (myfloat) => new PointValue(myfloat));
我的问题是如何为我的addPointToList
继承者创建PointValue
专门化,以避免传递创作者。
类似的东西:
public void addPointToList(float f)
{
this.addPointToList(f, (myfloat) => new PointValue(myfloat));
}
我试过这样做,但编译器说: 无法隐式转换类型&#39; PointValue&#39;到了PointValueT&#39;。存在显式转换(您是否错过了演员?)
我知道c#没有专业化,如果是这样的话,可能是某些&#34; design&#34;技巧可以帮助我吗? 让我们说我有PointValueA和PointValueB inherting,我怎样才能避免为每个人手动传递创作者?
答案 0 :(得分:2)
我原本以为处理这个问题的最基本方法是将工厂传递给构造函数,而不是每次调用addPointToList
。
public class PointList<PointValueT> where PointValueT : PointValue
{
public PointList(Func<float, PointValueT> pointValueCreator)
{
this.pointValueCreator = pointValueCreator;
}
Func<float, PointValueT> pointValueCreator;
private List<PointValueT> mylist = new List<PointValueT>();
public void addPointToList(float f)
{
mylist.Add(pointValueCreator(f));
}
}
然后会这样调用:
PointList<PointValue> bla = new PointList<PointValue>((myfloat) => new PointValue(myfloat));
bla.addPointToList(f);
答案 1 :(得分:1)
你不能像使用C ++中的模板一样专门化C#中的泛型。
能够在约束中指定构造函数参数(即where PointValueT : PointValue, new(float)
)会很好,但语言不允许这样做。
有几种解决方案可以实现您的目标:
1:使用像你一直在做的创作者模式
2:不是在构造函数中设置float,而是将其设置为属性。
public class PointValue
{
public float Value { get; set; }
}
public class PointList<PointValueT>
where PointValueT : PointValue, new()
{
public void addPointToList(float f)
{
// do something to f and then add a new point:
mylist.Add(new PointValueT { Value = f });
}
}
这确实意味着你不能使你的PointValue不可变。
答案 2 :(得分:1)
您可以使用继承进行专门化
public class PointValueList : PointList<PointValue>
{
public void addPointToList(float f)
{
addPointToList(f, (myfloat) => new PointValue(myfloat));
}
}
然后在那个新的继承或专业类上,你可以调用
bla.addPointToList(f);
另外,根据您的需要,您可以将基类抽象化并声明
public abstract void addPointToList(float f);
在基类中,然后在派生的专门化类中重写
但是,正如Enigmativity建议的那样,至少通过这个简单的例子,让工厂通过构造函数更有意义。