C# - Multiple Generic Types in One List

C# - Multiple generic types in one list

public abstract class Metadata
{
}

// extend abstract Metadata class
public class Metadata<DataType> : Metadata where DataType : struct
{
private DataType mDataType;
}

Storing a list of different generic types in a class

The T in a generic must be the same through out its lifetime.

for an example

var a = new MyClass<int>();
a.list.Add(1); //since a's generic T is declared as int the list is now also int

var b = new MyClass<string>()
b.list.Add("string"); //in b its now declared as a string and avccepts only string

So when you are doing this.

var c = new MyClass<IMyInterface>();
c.list.Add(ObjectImplementingIMyInterface); //You must add something that implements IMyInterface

The only thing you know about the content is that it implements IMyInterface now if you want to split the execution of the object then you must check the type of the object via reflection.

if(c.list[i].GetType() == typeof(ClassA_IMyInterface)
{
//Execute on ClassA_IMyInterface
//If you are after the ClassA
//and want to run something speciffic for it the cast
ClassA clA = = (ClassA)c.list[i];
//Now you have access to the implementation of ClassA instead of just the interface
}
else if (c.list[i].GetType() == typeof(ClassB_IMyInterface)
{
//Execute on ClassB_IMyInterface
}

Here is an example i made in ConsoleApplication showing how it lays out.

public class MyClass<T> where T : IMyInterface
{
public List<T> list = new List<T>();
}
public interface IMyInterface
{
}
public class Foo : IMyInterface
{
}
public class Bar : IMyInterface
{
}
public class FooBar
{
public void Test()
{
var content = new MyClass<IMyInterface>();
content.list.Add(new Foo());
if (content.list[0] is Foo)
{
//Execute on Foo
var g = (Foo)content.list[0];
//Now you can access Foo's methods and not only the Interfaces
Console.WriteLine("Foo");
}
else if (content.list[0] is Bar)
{
//Execute on Bar
var g = (Bar)content.list[0];
//Now you can access Bar's methods and not only the Interfaces
Console.WriteLine("Bar");
}
}
}

C# Generic List of Generic List of Multiple Types

The code you're building will be best understood if it models reality well.

The way to model "an A of B" is to use generics. A set of kinds of box that can hold one kind of thing would be modelled as Box<T>. A box that can only hold toys would be Box<Toy>. A set of kinds of box that can hold one kind of thing, and that thing has to be a toy would be a Box<T> where T : Toy.

So far so good. But the concept of Toy<T> doesn't map to anything in real life. You might have a box of biscuits or a box of toys, but you don't have a toy of biscuits, a toy of dolls or a toy of giraffes. The concept "toy of" doesn't make any sense, so don't model it.

A more sensible thing to model would be "there is a general class of things called toys. There is no one thing that is just a toy; every toy is a more specific kind of toy. A ball is a toy. A doll is a toy." So model that:

abstract class Toy {}
class Doll : Toy {}
class Ball : Toy {}

You said

I want Toy to be generic and accept a argument at instantiation because Toy must also have a List as a member.

Why? A toy does not have a list of things. So don't model that. Rather, a box is logically modelled as a list of the toys that are inside the box. (Or, since a box does not generally apply an ordering, and a box contains only unique toys, perhaps a set of toys would be better.)

I want to be able to create Toys with many different types and then insert them into a Box with another specified type.

OK. So an operation on Box<T> is void Insert(T item). You can put a toy into a box of toys, you can put a doll into a box of dolls, but you cannot put a ball into a box of dolls.

Then I'd like to be able to add boxes together returning a Box with the largest type.

You need to more carefully define "the largest type". If you add a box of dolls to a box of balls, clearly the result is neither a box of balls nor a box of dolls. The result is a box of toys.

Here's how I would model this. We already have the toy hierarchy. I would continue by saying that a box of T is implemented as a set of its contents, and provides a sequence of its contents.

// Haven't actually compiled this.
class Box<T> : IEnumerable<T>
{
private HashSet<T> set = new HashSet<T>();
public Insert(T item) { set.Add(item); }
public IEnumerator<T> GetEnumerator() { return set.GetEnumerator(); }
public IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); }

All very boring so far. Now we come to the interesting bit. This only works well in C# 4.

    public static Box<T> MergeBoxes(IEnumerable<T> box1, IEnumerable<T> box2)
{
Box<T> box = new Box<T>();
foreach(T item in box1) box.Insert(item);
foreach(T item in box2) box.Insert(item);
return box;
}
}

Now you can say

Box<Doll> dollbox = new Box<Doll>() { new Doll() };
Box<Ball> ballbox = new Box<Ball>() { new Ball() };
Box<Toy> toybox2 = Box<Toy>.MergeBoxes(ballbox, dollbox);

The result of merging a box of dolls with a box of balls is a box of toys.

This last bit only works because IEnumerable<T> is covariant in C# 4. In C# 3, this would be trickier to get right; you'd have to do something like:

Box<Toy> toybox2 = Box<Toy>.MergeBoxes(ballbox.Cast<Toy>(), dollbox.Cast<Toy>());

Does that make sense?

C# multiple generic types in method input and output collection

You could perhaps write it like

(T1 r1, T2 r2, T3 r3) Query<T1, T2, T3>(QueryModel q1,QueryModel q2,QueryModel q3 )

This would not allow an arbitrary number of queries, but you cannot have a variable number of generic arguments anyway, so I don't see any way to do that while keeping the generic types.

How do I specify multiple generic type constraints on a single method?

 public void foo<TTypeA, TTypeB>() where TTypeA : class, A 
where TTypeB : class, B

Multiple generic types in same list and calling their methods

I've tried a few things and I've found something that works pretty well for my needs. I have Rule<T> inherit from a base abstract rule class, with a generic IsBroken method:

abstract class Rule
{
string propertyName;
Func<object, bool> objectRule;

bool IsBroken<T>(T value)
{
Rule<T> rule = this as Rule<T>;
if (rule == null)
return objectRule(value);

return rule.IsBroken(value);
}
}

As you can see, I try to convert the base class to its generic counterpart using the generic type parameter in the IsBroken method.

Also, when creating a Rule<T> instance, I send a Func<object, bool> to its base class protected constructor:

public Rule(string propertyName, Func<T, bool> ruleLambda)
: base(propertyName, ConvertToObjectFunc(ruleLambda))
{
}

With the conversion method looking like this:

static Func<object, bool> ConvertToObjectFunc(Func<T, bool> func)
{
return new Func<object, bool>(o => func((T)o));
}

However, if it can't cast o to type T, it crashes. So I wrote this... thing:

static Func<object, bool> ConvertToObjectFunc(Func<T, bool> func)
{
return new Func<object, bool>
(
o =>
{
try
{
T obj = (T)o;
return func(obj);
}
catch { return true; } // rule is broken by default
}
);
}

It's pretty ugly, but it works. Hope this can help anybody else.

C# generics syntax for multiple type parameter constraints

void foo<TOne, TTwo>() 
where TOne : BaseOne
where TTwo : BaseTwo

More info here:

http://msdn.microsoft.com/en-us/library/d5x73970.aspx

Multiple generic types in one container

What would you do with md.Function if you could read it? You can't call it, because you don't know the parameter types. With C# 4.0, you could use dynamic, e.g. foreach (dynamic md in metadataObjects) and then you don't need the Metadata abstract base class. If you just want to access members of Delegate, you could change the abstract base class to an interface which has a Delegate Metadata { get; } property and explicitly implement it in Metadata<T>, then you could access e.g. the function's name.



Related Topics



Leave a reply



Submit