简体   繁体   English

通用类C#中的函数专业化

[英]Function specialization in generic class c#

I have a class called PointValue , PointValue and his inheritors can be created only by parametrized constructor that receives one float parameter. 我有一个称为PointValue的类, PointValue及其继承者只能由接收一个float参数的参数化构造函数创建。

I have a generic class that represents a list of points, template type must inherit from PointValue . 我有一个代表点列表的通用类,模板类型必须继承自PointValue

I need that one of the functions would have the ability to add points to the list, because I can't enforce using templates a parametrized constructor. 我需要其中一个功能能够将点添加到列表中,因为我无法使用模板来强制执行参数化的构造函数。 my function gets a pointValueCreator to create the new point. 我的函数得到一个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));
  }
}

So now if I have something like this: 所以现在如果我有这样的事情:

PointList<PointValue> bla = new PointList<PointValue>();

I can call my function like this: 我可以这样调用我的函数:

bla.addPointToList(f, (myfloat) => new PointValue(myfloat));

My question is how can I create specialization for addPointToList for my PointValue inheritors, to avoid passing creators. 我的问题是如何为PointValue继承者的addPointToList创建PointValue ,以避免传递创建者。

something like: 就像是:

public void addPointToList(float f)
{
this.addPointToList(f, (myfloat) => new PointValue(myfloat));
}

I've tried to do it, but the compiler says: Cannot implicitly convert type 'PointValue' to 'PointValueT'. 我尝试这样做,但是编译器说:无法将类型'PointValue'隐式转换为'PointValueT'。 An explicit conversion exists (are you missing a cast?) 存在显式转换(您是否缺少演员表?)

I understand that c# doesn't have specialization, if that is the case, maybe some "design" trick can help me ? 我了解C#没有专业知识,如果是这种情况,也许某些“设计”技巧可以帮助我? Let's say I have PointValueA and PointValueB inherting, how can i avoid passing creators for each one of them manually ? 假设我具有PointValueA和PointValueB继承关系,如何避免手动为每个创建者传递创建者?

I would have thought that the most basic way to handle this is by passing the factory through the constructor, rather than for each call to addPointToList . 我以为,处理此问题的最基本方法是通过工厂通过构造函数,而不是每次调用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));
    }
}

This would then be called like this: 然后将这样称呼它:

PointList<PointValue> bla = new PointList<PointValue>((myfloat) => new PointValue(myfloat));

bla.addPointToList(f);

You cannot specialise generic in C# like you can with templates in C++. 您不能像使用C ++中的模板那样专门化C#中的泛型。

It would be nice to be able to specify constructor arguments in constraints (ie where PointValueT : PointValue, new(float) ), but the language doesn't allow that. 能够在约束中指定构造函数参数(即where PointValueT : PointValue, new(float) )会很好,但是该语言不允许这样做。

There are a couple of solutions to achieve what you want: 有两种解决方案可以实现您想要的:

1: use a creator pattern like you're already doing 1:使用您已经在做的创作者模式

2: instead of setting the float in the constructor, set it as a property. 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 });
  }
}

This does mean you can't make your PointValue immutable though. 但这确实意味着您不能使PointValue不可变。

You can sort of specialize using inheritance 您可以使用继承来专门化

public class PointValueList : PointList<PointValue>
{
    public void addPointToList(float f)
    {
        addPointToList(f, (myfloat) => new PointValue(myfloat));
    }
}

and then on that new inherited or specialized class you can just call 然后在那个新的继承或专门类上,您可以调用

bla.addPointToList(f);

Also depending on your needs you can make the base class abstract and declare 另外,根据您的需要,您可以使基类抽象并声明

public abstract void addPointToList(float f);

in the base class and then override in derived specialization classes 在基类中,然后在派生的专业化类中重写

But yes, as Enigmativity suggested, passing factory through the constructor makes more sense at least with this simple example. 但是,是的,正如Enigmativity所建议的那样,至少通过此简单示例,使工厂通过构造函数更有意义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM