views:

45

answers:

2

In the context of C#, .Net 4...

Given a data source object that supplies vertices by index from an array of doubles where a vertex contains ten doubles with members Px, Py, Pz, Nx, Ny, Nz, S, T, U, V. and the backing array contains all or any subset of vertex members based on the data source's stride, offset and count properties. The data source could be simplified as:

  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;
    }
    .
    .
    .
  }

Some consumers would be interested in a return type of double[], but most would request data as a PointNf type where N is the number of vertex members taken (Point1f...Point10f). The Point type consumer does not care for the source's stride and the source supplies a zero for members greater than its stride. e.g. Point4f from a source of stride 3 would be filled with data[i + 0], data[i + 1], data[i + 2], 0.

Obviously DataSource could expose methods GetPoint1f(int index), GetPoint2f(int index) and the like. These types of solutions might be best given the fixed set of return types, element size, etc. However...

What are possible solutions if a syntax like…

Point3f point = SomeDataSource.ElementAt[index];

...or similar was requested/required/desired ?...pros/cons ?...examples of what not to do ?...harsh language ?

+4  A: 

What are possible solutions if a syntax like…

Point3f point = SomeDataSource.ElementAt[index];

...or similar was requested/required/desired ?

This is the prime candidate for a user-defined implicit conversion:

// 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 };
    }
}
Timwi
Thanks for the kick in the head. Sometimes the world of classes, interfaces, abstracts, generics, etc. is the forest for the trees.
Rusty
+1  A: 

How do you know the type of PointNf which is at index?

Anyway, the factory pattern is what you're after, but the question is how you will implement it given your objects. A basic factory would look something like this

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;
}

NB: This won't compile because X, Y, Z aren't defined for T, but you don't wanna use this anyway.

The drawback is having to check for the type of T for each point type. There are several solutions to improve on it though if you are using your own PointNf classes which you can modify. An example would be to make each PointNf class derive from a common interface (IPointDataProvider) with a method like void PopulateData(double[] data, int index), for which they implement their own specifics, and your factory method can be reduced to

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

An example implementation of a point is as simple as.

class Point2f : IPointDataProvider {
    double X, Y;

    void IPointDataProvider.PopulateData(double[] data, int index) {
        X = data[0];
        Y = data[1];
    }
}
Mark H
...type of PointNf which is at index?...The consumer's context defines the type required and the index list used against the data source. Some consumers take vertex and normal data as two separate lists of Point3f another may take a single Point6f list. Sometimes there are multiple data sources (one for normals, one for verts, etc.) and sometimes there is one data source for all...just depends on the nature of the data source.
Rusty