AndyB
AndyB

Reputation: 1946

How do you create a type-safe array or collection with varying types of individual elements?

I'm implementing a method in C# that takes a single argument of type object, e.g. SomeMethod(object argument). I need to pass a collection of multiple objects of varying type to this method. I can't change the method signature because of interface restrictions.

I was thinking of sending an object array, object[] myArray = new object[2], but I want to strongly type each element of the array if possible. For example, I have two objects, one of type Foo and the other of Bar. I want to guarantee that myArray[0] is Foo and myArray[1] is Bar.

How would I do this? Would another collection type or creating a special class make more sense?

UPDATE: All good answers. Tuple looks the most generic way but as I said in the comment, I'm limited to 3.5. A struct would work but after a little research on using structs vs classes as arguments, there is a slight performance hit if you use a larger struct. (Source - see Benchmark section). So I'm going to go with a class. Thank you all!

Upvotes: 4

Views: 1029

Answers (4)

CodingWithSpike
CodingWithSpike

Reputation: 43698

You might be better off with a Tuple<>, for example:

Foo foo = new Foo();
Bar bar = new Bar();
Tuple<Foo, Bar> fooBar = new Tuple(foo, bar);
SomeMethod(fooBar);

But without further info on your code, its hard to tell whether that would fit your needs better than an object[].

Upvotes: 1

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112279

Create a class or struct that reflects your need

public class FooBar
{
    public Foo Foo { get; set; }
    public Bar Bar { get; set; }
}

Then call your method like this

SomeMethod(new FooBar { Foo = foo, Bar = bar });

Implement it like this

public SomeMethod(object argument)
{
    var fooBar = argument as FooBar;
    if (fooBar != null) {
        Foo foo = fooBar.Foo;
        Bar bar = fooBar.Bar;
        ...
    }
}

Upvotes: 1

Miserable Variable
Miserable Variable

Reputation: 28752

I want to guarantee that myArray[0] is Foo and myArray[1] is Bar

An Array is collection of objects of some type. So you cannot guarantee this. The only way to do this is to create a composite type, a struct or a class.

But if your signature SomeMethod(object argument) is fixed, you would still not be able to guarantee that statically inside that method. The best you can do is to externally make sure you are passing argument of the correct type.

Upvotes: 2

JaredPar
JaredPar

Reputation: 754545

The only way to safely store a set of unrelated types in a collection is to use an intermediate type which restricts values to those types and store that type in the collection. It's a poor man's discriminated union.

sealed class FooOrBar {
  public readonly Foo Foo;
  public readonly Bar Bar;
  public bool IsFoo { 
    get { return Foo != null; }
  }
  public bool IsBar {
    get { return Bar != null; }
  }
  public FooOrBar(Foo f) {
    Foo = f;
  }
  public FooOrBar(Bar b) {
    Bar = b;
  }
  public static implicit operator FooOrBar(Foo f) {
    return new FooOrBar(f);
  }
  public static implicit operator FooOrBar(Bar b) {
    return new FooOrBar(b);
  }
}

FooOrBar[] array = new FooOrBar[2];
array[0] = new Foo();
array[1] = new Bar();
array[2] = "test";  // Fails to compile

Upvotes: 2

Related Questions