有哪些动态/通用/其他方法可以根据调用者的类型生成返回类型?

时间:2010-09-01 23:25:46

标签: c# .net generics dynamic

在C#,.Net 4 ...

的背景下

给定一个数据源对象,该对象通过索引从双精度数组中提供顶点,其中顶点包含10个双精度数,其成员为Px,Py,Pz,Nx,Ny,Nz,S,T,U,V和后备数组包含基于数据源的步幅,偏移和计数属性的所有顶点成员的任何子集。数据源可以简化为:

  public class DataSource
  {
    private double[] data;
    private int offset, stride, count;

    public double[] ElementAt(int index)
    {
      double[] result = new double[count];
      var relativeIndex =  index * stride + offset;
      Array.Copy(data, relativeIndex, result, 0, count);
      return result;
    }
    .
    .
    .
  }

一些消费者会对double []的返回类型感兴趣,但大多数会将数据作为PointNf类型请求,其中N是所采用的顶点成员数(Point1f ... Point10f)。 Point类型的消费者不关心源的步幅,而源为大于其步幅的成员提供零。例如来自步幅3的来源的Point4f将填充数据[i + 0],数据[i + 1],数据[i + 2],0。

显然,DataSource可以公开方法GetPoint1f(int index),GetPoint2f(int index)等。这些类型的解决方案可能最好给出固定的返回类型集,元素大小等。但是......

如果语法如...

,有哪些可能的解决方案
Point3f point = SomeDataSource.ElementAt[index];

...或者类似的是被要求/要求/想要的?...利弊?...什么不该做的例子?......严厉的语言?

2 个答案:

答案 0 :(得分:5)

  

如果语法如...

,有哪些可能的解决方案
Point3f point = SomeDataSource.ElementAt[index];
     请求/要求/期望

...或类似的?

这是用户定义的隐式转化的主要候选者:

// I’m guessing it’s a struct, but can be a class too
public struct Point3f
{
    // ...

    public static implicit operator Point3f(double[] array)
    {
        // Just for demonstration: in real code,
        // please check length and nullity of array first!
        return new Point3f(array[0], array[1], array[2]);
    }

    // You can declare one that goes the other way too!
    public static implicit operator double[](Point3f point)
    {
        return new double[] { point.Px, point.Py, point.Pz };
    }
}

答案 1 :(得分:1)

您如何知道index处的PointNf类型?

无论如何,工厂模式就是你所追求的,但问题是如何根据你的对象实现它。基本工厂看起来像这样

public T GetElementAt<T>(int index) where T : new() {
    Type type = typeof(T);
    T result = new T()
    if (type==typeof(Point3f)) {
        result.X = data[index];
        result.Y = data[index+1];
        result.Z = data[index+2];
    }
    else if (type==typeof(Point2f) {
        result.X = data[index];
        result.Y = data[index+1];
    }
    return result;
}

注意:这不会编译,因为X,Y,Z没有为T定义,但你不想再使用它。

缺点是必须检查每种点类型的T类型。如果您使用自己可以修改的PointNf类,有几种解决方案可以改进它。一个例子是使每个PointNf类使用类似IPointDataProvider的方法从公共接口(void PopulateData(double[] data, int index))派生,为此它们实现自己的细节,并且您的工厂方法可以简化为

public T GetElementAt<T>(int index) where T : IPointDataProvider, new() {
    T result = new T()
    result.PopulateData(data, index)
    return result;
}

一个点的示例实现就像。

一样简单
class Point2f : IPointDataProvider {
    double X, Y;

    void IPointDataProvider.PopulateData(double[] data, int index) {
        X = data[0];
        Y = data[1];
    }
}