Martin
Martin

Reputation: 2971

function to take array of arbitrary type in c#

I've made a function that processes an array of objects, process(Object[]). It works on any type including integers and floats so long as you box each element first. I'd like the function to take unboxed elements aswell, if only to box it itself before processing. How do I do that?

I could wrap with a few functions like process(int[]) and process(float[]) but that also seems a hassle. I've tried process(ValueType[]) but the compiler still selects process(Object[]).

I have C# 2.0, but if there is a nice solution for 3.0 I'd like to see it.

Upvotes: 5

Views: 3585

Answers (5)

Romain Verdier
Romain Verdier

Reputation: 13011

Well, technically, it is possible. But it's not recommended, nor useful, for obvious reasons. Note that it performs badly too, and doesn't allow you pass arrays directly.

For curiosity and weirdness sake, here is the trick. It uses TypedReference and undocumented C# keywords.

public void Process(__arglist)
{
    var iterator = new ArgIterator(__arglist);
    do
    {
        TypedReference typedReference = iterator.GetNextArg();
        Type type = __reftype(typedReference);
        if (type == typeof(int))
        {
            int value = __refvalue( typedReference,int);
            // value is an int
        }
        else if (type == typeof(string))
        {
            string value = __refvalue( typedReference,string);
            // value is a string
        }
        else if (type == typeof(double))
        {
            double value = __refvalue( typedReference,double);
            // value is a double
        }
        // etc.
    }
    while (iterator.GetRemainingCount() > 0);
}

You can call the method like that:

Process(__arglist(45, "lol", 42.5));

It will not box/unbox values types. But, well, forget that...

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1503819

How does the processing work? The most obvious method signature would be:

void ProcessArray<T>(T[] data)

That is literally "an array of an arbitrary type" - although the type needs to be known by the caller at compile-time.

However, depending on how you use the elements, you may still end up boxing. Maybe that's okay, given the part of your question which says: "if only to box it itself before processing". If you're happy enough with that, great :)

If you could give more details of what you're doing, we may be able to help more.

Upvotes: 7

Vinay Sajip
Vinay Sajip

Reputation: 99520

Boxing is implicit. For example:

using System;

namespace MyProg
{
  class Program
  {

    private static void ParamTest(params object[] args)
    {
      foreach (object o in args)
      {
        Console.Write(o);
        Console.WriteLine(", ");
      }
      Console.WriteLine();
    }

    static void Main(string[] args)
    {
      ParamTest(1, "abc", 2.4, new object());
    }
  }
}

will print

1,
abc,
2.4,
System.Object,

Not a generic in sight!

Upvotes: 0

Eamon Nerbonne
Eamon Nerbonne

Reputation: 48166

Short answer: you can't (usefully) do this. Generics might seem to be a way around this, but as soon as you actually use the generically typed instance, you'll be passing it to methods that must accept class object - so it'll be boxed then (worse; it'll be boxed many times probably, depending on your code).

If you want to gain performance by avoiding boxing generically, you'll need to work on how you process these instances and ensure that all processing can occur in a type-safe manner despite the generic approach - and that's not easy (see Generic Numerics for example) and depends heavily on the processing you need to do.

Upvotes: 0

KV Prajapati
KV Prajapati

Reputation: 94653

 static void T(Array a)
    {
        if (a is int[])
            Console.WriteLine("Int");
        else
            if (a is float[])
                Console.WriteLine("Float");
            else
                ....

    }
    static void Main(){
        T(new int[]{30});
        float[] a = { 11 };
        T(a);
    }

Upvotes: 0

Related Questions