Skip to content

Using Transform

Lorenz Lo Sauer edited this page Oct 3, 2016 · 2 revisions

Transform is useful in situations wherein the input and output type are similar or the same. Aside from linguistics the implementation is similar. All Types involved in the conversion must be from the same namespace.

If the optional parameter strictTypeCheck is set to true, an exception will be thrown if the input and output types do not match. This does not hold true for the Try version, which has no optional strictTypeCheck argument.

In the following example, a converter transposing a 2x2 Square matrix is implemented. Aptly, Transform is invoked as the output and input types match.

Transformations are different from Convert and Cast operations in that there can be disambiguate functions, all of which operate on the same input-, output- and model parameter types, yet may yield completely different values.

As such, converters should be assigned by named aliases or delegates. Follow best-practices by using a transform enumerable. However a string argument may be passed as alias as well.

Additionally, best-practices recommend that an assertively named delegate is declared, as explicatively shown in the following code sample:

Example for simple matrix operations

    delegate float[,] Transpose2x2(float[,] matrix, object model);

    // Transpose 2x2 matrix converter:
    // { { a, b}, { c, d } } -> 1/(ad -bc)* { {d, - b }, {- c,  a} }
    ConverterCollection.CurrentInstance
        .Add<float[,], float[,], Transpose2x2>((a) => {
            float _f = 1 / (a[0, 0] * a[1, 1] - a[0, 1] * a[1, 0]);
            return new float[,] { { _f * a[1, 1], -_f * a[0, 1] }, { -_f * a[1, 0], _f * a[0, 0] } };
        });

    var matrix2x2 = new float[,] 
    { 
        { 0, 1 }, 
        { 2, 3 } 
    };

After adding the custom transformer-algorithm, the given matrix may be transformed by passing the delegate type of the transformer function, and declaring the output Type as the second generic parameter, or alternatively following up with a subsequent cast operation as shown below:

    float[,] matrixTransposedExample1 = matrix2x2.Transform<Transpose2x2, float[,]>();
    
    // alernatively, you may follow up with a cast statement:
    float[,] matrixTransposedExample1 = matrix2x2.Transform<Transpose2x2>().CastTo<float[,]>();

Alternatively, the delegate may be passed as a type argument, in case the output and input types do match:

    float[,] matrixTransposedExample1 = matrix.Transform(typeof(Transpose2x2));

    // with a second "model" parameter
    float entropyValue = matrix.Transform("Shannon", typeof(Entropy));
    // the same example with named arguments
    float entropyValue = matrix.Transform(typeBase: typeof(Entropy), model: "Shannon");

The example using Transpose2x2`` will yield the transposed of input matrix2x2` as follows:

    matrixTransposedExmpl1 = {float[2, 2]}:
        [0, 0]: -1.5
        [0, 1]: 0.5
        [1, 0]: 1
        [1, 1]: 0

When the input and output types do not match, a subsequent implicit or explicit cast operation is required as follows:

    delegate float[,] Transpose1xN(float[] matrix);

    ConverterCollection.CurrentInstance
        .Add<float[], float[,], Transpose1xN>((a) => {
            var result = new float[a.Length, 1];
            for(int i = 0; i < a.Length; result[i, 0] = a[i], i++) ;
            return result;
        });

    var matrixTransposed1x = (float[,])new []{ 1f, 2f, 3f, 4f}.Transform<Transpose1xN>();

    // yielding:
    matrixTransposed1x = {float[4, 1]}
        [0, 0]: 1
        [1, 0]: 2
        [2, 0]: 3
        [3, 0]: 4

Additionally, particularly with interactive-shells in mind, Transform allows adding an aliased function and computing in one invocation, with the full benefit of strong typed IDE introspection, as follows:

    // list the tranform-function aliases here
    public enum Transform
    {
        Matrix2x2Determinant,
        MatrixAnotherOperation,
        ...
    }

    // declare and add a transformer, whilst computing the result, with a strongly typed result in both cases
    var matrixTransposedEx2 = matrix2x2.Transform( (a) => a[0,0]*a[1,1] - a[0,1]*a[1,0], Transform.Matrix2x2Determinant);

    var matrixTransposedEx2_ = matrix2x2.Transform<float>( Transform.Matrix2x2Determinant);

A real-case scenario of using Transform is provided in Example11.