none
System.Array cast to multidimensional array T[,] or T[,,] (etc) depending on Array.Rank RRS feed

  • Question

  • Hi! 

    I have a set of functions that perform the same task over an input T[] or T[,] or T[,,] depending on Array.Rank property.

    I succesfully implemented a single generalized function taking as input System.Array an iterating through the dimensions, however i'd like to return the correct type T[] or T[,] or T[,,] istead of a generic System.Array.

    How can i cast System.Array back to the correct T[*] type?

    Thank you. 

    Thursday, May 10, 2012 9:03 PM

Answers

  • Below is a class that illustrates a VB way of doing what you want.  The price you pay for maximum coding convenience is a pass through overload (to function f).  Absent this, you have to do the ctype where f is called.  In the class, function f represents a function you might want, and the supplied example just returns a clone.  The test sub at the bottom compiles clean with option strict on, and it produces the output you would expect.  The bottom test involving p(,,) and q(,,) illustrates how to do things without a pass through.  Notice that this invocation of f is a lot busier than when a pass through is available.

    Public Class ggg
      Public Shared Function f(Of T)(ByVal a As Array) As Array
        ' here is where a function is coded for any rank
        ' this sample just returns a clone of its input
        Return CType(a.Clone, Array)
      End Function
      Public Shared Function f(Of T)(ByVal a As T()) As T()
        ' passthrough override for rank=1
        Return CType(CType(a, Array), T())
      End Function
      Public Shared Function f(Of T)(ByVal a As T(,)) As T(,)
        ' passthrough override for rank=2
        Return CType(CType(a, Array), T(,))
      End Function
      Public Shared Sub test()
        ' test driver
        Dim x() As String = {"a", "b"}
        Dim y() As String = f(x)
        Dim a(,) As Integer = {{1, 2, 3}, {4, 5, 6}}
        Dim b(,) As Integer = f(a)
        Dim p(1, 1, 1) As Double : p(1, 1, 1) = 10
        ' below is less convenience but equal functionality
        Dim q(,,) As Double = CType(f(Of Double)(p), Double(,,))
      End Sub
    End Class

    • Marked as answer by Heartbreaka Friday, May 11, 2012 10:22 AM
    Thursday, May 10, 2012 9:48 PM
  • "  public static T Task<T>( this Array a )

    T should be int[] or int[,] but never int. "

    The only way to do this in C# is to have 3 separate functions like:

    public static T[] Task<T>(this T[] a)

    public static T[,] Task<T>(this T[,] a)

    public static T[,,] Task<T>(this T[,,] a)

    But this is pretty much the same thing as amercer shows in his first post.

    PS:

    What you want implies that the return type of a function is decided at runtime, that's not possible. C# is statically typed, the return type must be known at compile time.


    Friday, May 11, 2012 10:01 AM
    Moderator

All replies

  • "How can i cast System.Array back to the correct T[*] type?"

    But if this is the same array that the function got as input it is already of the correct type, there's nothing to cast.

    Thursday, May 10, 2012 9:17 PM
    Moderator
  • Below is a class that illustrates a VB way of doing what you want.  The price you pay for maximum coding convenience is a pass through overload (to function f).  Absent this, you have to do the ctype where f is called.  In the class, function f represents a function you might want, and the supplied example just returns a clone.  The test sub at the bottom compiles clean with option strict on, and it produces the output you would expect.  The bottom test involving p(,,) and q(,,) illustrates how to do things without a pass through.  Notice that this invocation of f is a lot busier than when a pass through is available.

    Public Class ggg
      Public Shared Function f(Of T)(ByVal a As Array) As Array
        ' here is where a function is coded for any rank
        ' this sample just returns a clone of its input
        Return CType(a.Clone, Array)
      End Function
      Public Shared Function f(Of T)(ByVal a As T()) As T()
        ' passthrough override for rank=1
        Return CType(CType(a, Array), T())
      End Function
      Public Shared Function f(Of T)(ByVal a As T(,)) As T(,)
        ' passthrough override for rank=2
        Return CType(CType(a, Array), T(,))
      End Function
      Public Shared Sub test()
        ' test driver
        Dim x() As String = {"a", "b"}
        Dim y() As String = f(x)
        Dim a(,) As Integer = {{1, 2, 3}, {4, 5, 6}}
        Dim b(,) As Integer = f(a)
        Dim p(1, 1, 1) As Double : p(1, 1, 1) = 10
        ' below is less convenience but equal functionality
        Dim q(,,) As Double = CType(f(Of Double)(p), Double(,,))
      End Sub
    End Class

    • Marked as answer by Heartbreaka Friday, May 11, 2012 10:22 AM
    Thursday, May 10, 2012 9:48 PM
  • Handling arrays is very depended of the program language you use. Are you using C++ or F#, I suggest you to ask this in the forum from the program language which you are using.

    For instance VB declares sometimes an extra item when constructed.


    Success
    Cor

    Friday, May 11, 2012 5:34 AM
  • Or you can code in the style below which is fairly simple.  This works because arrays of various ranks can be widened to type 'Array'.  You have to be explicit at the call about the type and rank, and if you get this wrong, you will get a runtime error vice a compile time diagnostic.

      Public Shared Function g(Of T)(ByVal a As Array) As T
        ' here is where a function is coded for any rank
        ' this sample just returns a clone of its input
        Return CType(a.Clone, T)
      End Function
      Public Shared Sub Test()
        ' test driver
        Dim x() As String = {"a", "b"}
        Dim y() As String = g(Of String())(x)
        Dim a(,) As Integer = {{1, 2, 3}, {4, 5, 6}}
        Dim b(,) As Integer = g(Of Integer(,))(a)
        Dim p(1, 1, 1) As Double : p(1, 1, 1) = 10
        ' runtime error because of (x) vice (p)
        Dim q(,,) As Double = g(Of Double(,,))(x)
        Return
      End Sub

    Friday, May 11, 2012 6:25 AM
  • This is incorrect: Function should be something like:

    Public Shared Function f(Of T)(ByVal a As Array) As T

    oherwise i should not need a cast.

    Any idea?

    Friday, May 11, 2012 9:19 AM
  • This seems to be what i did in C#; anyway in C# you need to bound T to be a array or something but this is not possible.. to be more clear this is the code 

           public static T Task<T>( this Array a )

    T should be int[] or int[,] but never int. 

    In C# this leads to compile error cause (without bounds) I cannot assume T is an array or something "indexed".

    So I should bound T to something "indexed" but this does not seem to be possible.

    Any idea for C#?

     
    Friday, May 11, 2012 9:30 AM
  • I don't want to return an Array type but the correct T[] type that is:

      public static Array Task<T>( this Array a ) // I don't want this

      public static T Task<T>( this Array a ) // I want this

    Friday, May 11, 2012 9:33 AM
  • "  public static T Task<T>( this Array a )

    T should be int[] or int[,] but never int. "

    The only way to do this in C# is to have 3 separate functions like:

    public static T[] Task<T>(this T[] a)

    public static T[,] Task<T>(this T[,] a)

    public static T[,,] Task<T>(this T[,,] a)

    But this is pretty much the same thing as amercer shows in his first post.

    PS:

    What you want implies that the return type of a function is decided at runtime, that's not possible. C# is statically typed, the return type must be known at compile time.


    Friday, May 11, 2012 10:01 AM
    Moderator
  • OK I'll go this way. Thank you all.
    Friday, May 11, 2012 10:21 AM