tags:

views:

351

answers:

6
+3  Q: 

C# Generic Lists

I have a class that is maps to a field in a database. The class only cares about the name of the field and its related .NET type. The type can be string, int, datetime, etc.

class Foo()
{
    string Name { get; set; }
    Type FooType { get; set; }
}

I have another class that inherits from Foo that adds a property for a value. Right now I store the value as an object and use a switch statement to box the value based on the base classes FooType.

class FooWithStuff() : Foo
{
    object Value { get; set; }   
}

Is there way to implement this with generics to give type safety for the values?

Edit: I have made the key requirement bold. When declaring a list say Foo it needs a type. If I were doing this against custom classes I would create and interface and use that. However here I am using int, string, DateTime, etc. Int is a struct, string is an object, so a Foo< object> does not work for both.

+1  A: 

I would use an Interface rather than a generic class inheritance on that.

edit: To clarify. I would use an Interface for Foo, and a generic class for FooWithStuff:

public interface IFoo
{
  string Name{get;set;}
  Type FooType{get;set;}
}

public class FooWithStuff<T>:IFoo
{
   T Value {get;set;}
}
Mike_G
Why would you keep the Type on the interface, it isn't needed for the conversion?
blu
I guess I am missing the point.@divo, ya i kinda assumed to much on that.
Mike_G
+2  A: 

If you want to add Value to Foo and have Foo be generic you could do...

class Foo<T>
{
    T Value {get; set;}
}

Foo<int> myFoo = new Foo<int>();
myFoo.Value = 7;
Quintin Robinson
But this would not fulfill the additional constraint that T is the same type as FooType?
0xA3
You wouldn't store FooType anymore: instead you could call Foo<T>.GetType().GetGenericArguments[0]
Joel Coehoorn
Or make a property that returns that: public Type FooType { get { return typeof(T); } }
configurator
I guess that is what I was going for, I didn't see a need for FooType if you have the type in mind. If you still want to cast to a base you could implement a Foo interface, i'll post an example.
Quintin Robinson
+9  A: 
class Foo
{
    public string Name { get; set; }
    public Type Type { get; set; }
}

class Bar<T> : Foo
{
    public T Value { get; set; }

    public Bar()
    {
     base.Type = typeof( T );
    }
}
kitchen
A: 

Yes, in fact you can do away with your inheritance, simply..

public class Foo<T>
{
  public string Name {get;set;}
  public T Value {get;set;}
  public Type FooType
  {
     get
     {
       return typeof(T);
     }
  }
}

Note also, using linq you can simply extract the types you need from the list directly, so if you are just interested in the string fields for some reason you could...

List<object> list = getAllmyFoos();
foreach(Foo<string> sfoo in list.OfType<Foo<string>>())
{
  ...blah
}

Edit : Added FooType.

Tim Jarvis
The issue is when I declare the List it needs a type, and it stores ints, strings, and datetimes, etc
blu
Sure. If you need it you need it.
Tim Jarvis
+8  A: 

Define your class like this:

class Foo<T> : IFoo
{

    public Foo(string name)
    {
        Name = name;
    }

    string Name { get; set; }
    T Value {get; set;}
    Type FooType { get { return typeof(T); } }
}

You could then define the interface IFoo as:

string Name { get; set; }
Type FooType { get; set; }

And declare a list as:

List<IFoo> list = new List<IFoo>();
Lars Mæhlum
This looks like the most complete, accurate, and cleanest implementation. I am currently trying it out.
blu
A: 

I would recomand using 2 interfaces :

public interface IFoo
{
  string Name {get; }
  Type Type { get; }
  object Value {get; set;}
}

public interface IFoo<T> : IFoo
{
  T Value {get; set}
}

Then implement it :

public class Foo<T> : IFoo<T>
{
   private T value;
   public Foo(string name, T value)
   {
     this.name = name;
     this.value = value;
   }

   public string Name { get { return name; } }
   public Type Type { get { return typeof(T); } }
   public T Value
   {
      get { return value; }
      set { value = value; }
   }

   object IFoo.Value
   {
      get { return value; }
      set { value = (T)value; }  // can check type before
   }
}

This way, you can use the IFoo interface easily in a non generic context too.

Think Before Coding