Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to use a list of untyped generics in C#?

Tags:

c#

list

generics

I'm trying the following design without success:

abstract class Foo<T>
{
    abstract T Output { get; }
}

class Bar
{
    List<Foo> Foos;
}

I would dislike using an array list, because I would have to use unsafe casts to get the type. I'd like Foo to be typed so that "Output" isn't just an object, in which case I'd have to use unsafe casts as well.

As my code is at the moment, I use Foo untyped with Output as an object.

like image 542
Lazlo Avatar asked Aug 31 '10 23:08

Lazlo


People also ask

Can we store different data types in list in C#?

We can use an ArrayList class that is present in the System. Collections namespace,. Using it we can store different types because the ArrayList class operates on the object type.

When to use generic class c#?

Generic classes encapsulate operations that are not specific to a particular data type. The most common use for generic classes is with collections like linked lists, hash tables, stacks, queues, trees, and so on.

Is list a generic class C#?

In c#, List is a generic type of collection, so it will allow storing only strongly typed objects, i.e., elements of the same data type. The size of the list will vary dynamically based on our application requirements, like adding or removing elements from the list.


1 Answers

If I understand you correctly, you want a list of Foo objects which have different types of Outputs, right? Since these outputs are of different types, you would have to use casts here anyway.

However, the following idea might help. How about you declare a non-generic interface called IFoo: ¹

public interface IFoo
{
    object Output { get; }
}

and then implement it in your abstract class:

abstract class Foo<T> : IFoo
{
    abstract T Output { get; }
    object IFoo.Output { get { return Output; } }
}

Then you can declare a list of IFoos:

class Bar
{
    List<IFoo> Foos;
}

When accessing those foos, you can either retrieve the output as an object via the interface:

var myObject = Foos[0].Output;     // type ‘object’

or you can try to discover the real type if you know that it can only be one of a few specific types:

if (Foos[0] is Foo<string>)
    var myString = ((Foo<string>) Foos[0]).Output;   // type ‘string’

You can even do filtering based on the type, for example:

// Type ‘IEnumerable<string>’ (rather than ‘IEnumerable<object>’)!
var stringFoos = Foos.OfType<Foo<string>>().Select(f => f.Output);

¹ You can also make this an abstract base class called Foo and have Foo<T> derive from it. In that case, you would need to mark Foo<T>.Output with the new keyword and use base.Output to access the abstract base member.

like image 75
Timwi Avatar answered Oct 05 '22 22:10

Timwi