泛型类c#中的函数专门化

时间:2015-11-05 22:41:41

标签: c# generics

我有一个名为PointValuePointValue的类,他的继承者只能通过接收一个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,我怎样才能避免为每个人手动传递创作者?

3 个答案:

答案 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建议的那样,至少通过这个简单的例子,让工厂通过构造函数更有意义。