views:

350

answers:

8

How do I allow my CookieData to be generic in the following code? I get an compile-time error on the declaration of ICookieService2.

public struct CookieData<T>
{
    T Value { get; set; }
    DateTime Expires { get; set; }
}

public interface ICookieService2: IDictionary<string, CookieData<T>>
{
   // ...
}

My error is:

The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?)

I am wanting ICookieService2 to have generic data inserted into it. Thanks!

Edit Won't that lock me into a single T for the construction of any ICookieService2?

Edit 2 What I am trying to do is the following:

CookieData<int> intCookie = { Value = 27, Expires = DateTime.Now };
CookieData<string> stringCookie = { Value = "Bob", Expires = DateTime.Now };

CookieService2 cs = new CookieService2();
cs.Add(intCookie);
cs.Add(stringCookie);
+4  A: 

You must make ICookieService2 generic as well:

public interface ICookieService2<T>: IDictionary<string, CookieData<T>>
{
   // ...
}
Lasse V. Karlsen
+2  A: 

OK, here's what you want:

public interface ICookieDataBase
{
    DateTime Expires { get; set; }
}

public struct CookieData<T> : ICookieDataBase
{
    public T Value { get; set; }
    public DateTime Expires { get; set; }
}

public class ICookieService : IDictionary<string, ICookieDataBase>
{
    // ...
}

public void DoWork()
{
    var intCookie =
        new CookieData<int> { Value = 27, Expires = DateTime.Now };

    var stringCookie =
        new CookieData<string> { Value = "Bob", Expires = DateTime.Now };

    ICookieService cs = GetICookieService();
    cs.Add(intCookie);
    cs.Add(stringCookie);
}
mquander
A: 

not sure about C#, but the Java way would be to also declare your ICookieService2 to have the <T> parameter, or to specify the <T> to something concrete in CookieData.

Jorn
ok, seeing from above answers this is correct :)
Jorn
+1  A: 

I think what you want is:

public interface ICookieService2<T>: IDictionary<string, CookieData<T>>
{
   // ...
}

currently ICookieService2 is not generic, so T is not defined.

This allows you to create classes the implement ICookieService2<string> or ICookieService2<int>, etc.

EDIT: Responding to your latest request, I think it really depends on exactly what it is you need. However, something like this may work for you.

public interface ICookieData
{
    object Value {get;} // if you need to be able to set from CookieService, life gets harder, but still doable.
    DateTime Expires {get;}
}

public struct CookieDate<T> : ICookieData
{
    T Value {get;set;}
    DateTime Expires {get;set;}

    object ICookieData.Value
    {
        get
        {
            return Value;
        }
    }
}

Then CookieService can be or have a List and you would be able to add both CookieData and CookieData. If you need to be to write (set) from CookieService, its a little more complicated, and possibly better to not use generics. But if you just need to be able to retrieve the CookieData, then this might work for you.

Timothy Carter
+1  A: 

You need a non-generic interface to do this:

public interface ICookieData
{
  // you need this to get the value without knowing it's type
  object UntypedValue { get; }
  // whatever you need additionally ...
  Type DataType { get; } 

  DateTime Expires { get; set; }
}

public struct CookieData<T> : ICookieData
{
    // ICookieData implementation
    public object UntypedValue { get { return Value; } }
    public Type DataType { get { return typeof(T); } }
    public DateTime Expires { get; set; }

    // generic implementation
    T Value { get; set; }
}

public interface ICookieService2: IDictionary<string, ICookieData>
{
   // ...
}

CookieData<int> intCookie = { Value = 27, Expires = DateTime.Now };
CookieData<string> stringCookie = { Value = "Bob", Expires = DateTime.Now };

CookieService2 cs = new CookieService2();
cs.Add(intCookie);
cs.Add(stringCookie);
Stefan Steinegger
+5  A: 

It looks like you have 3 options here

Make ICookieService2 generic

public interface ICookieService2<T> : IDictionary<string, CookieData<T> {
...
}

Create a non-generic base class for CookieData and use that in the interface

public interface ICookieData {}
public class CookieData<T>: ICookieData{}
public interface ICookieService2 : IDictionary<string, ICookieData> {}

Pick a concrete implementation

public interface ICookieService : IDictionary<string, CookieData<int>> {}
JaredPar
A: 

If I understand your question correctly you are wanting to treat the generic types like they are the same, but in current .NET implementation you can't do this.

CookieData<string> can't be passed as a CookieData<int> they are actually different types, the generic types are not related and can't be cast or passed like they are the same. Creating ICookieService2 as an open generic (meaning ICookieService2<T>) doesn't solve the problem because then you would have a different ICookieService2 type for every different type and all of them would be in a different dictionary.

You can create a ICookieData interface and implement it in CookieData<T> and use ICookieData to store the items in the dictionary (as Stefan has already suggested).

You can do what you want in C# 4.0 (with a few restrictions). There is an article about it here until then, you have to pass it as a non-generic type that is common to them such as an interface or just have the value parameter be an object on the dictionary because you are going to have to case it to use it anyway if you are using primitives as the type arguments.

Brian ONeil
A: 

You could try

public struct CookieData<T>
    where T : Object
{
    T Value { get; set; }
    DateTime Expires { get; set; }
}

That way all instances of T would be forced to have a base type of Object. (pretty much everything in C# (e.g. int == System.Integer etc.).

zonkflut
That doesn't work.
Daniel A. White