3

i have a basic DataTag class defined in this way:

public abstract class DataTag<TRaw, TVal>
{
    public abstract TVal Value { get; }
    public TRaw RawValue { get; set; }
    public string Name { get; private set; }
    public string Desc { get; private set; }
}

where TRaw is raw data taken from a device, while TVal is the "formatted" value.

So i may have 2 tags from same device:

DataTag t1 = DataTag.Create<ushort,int>();
DataTag t2 = DataTag.Create<ushort[],float()>;

Now i have a class which should contain a list of generic tags

private IEnumerable<DataTag<?,?> _tags();

Of course C# will not accept different kind of generic in the same list, but this is what i would like to achieve. Any tip for that?

SpaceBison
  • 3,704
  • 1
  • 30
  • 44
Vincenzo
  • 1,549
  • 1
  • 9
  • 17
  • It's similar to this question. You have code example here: http://stackoverflow.com/questions/1541152/c-sharp-generic-where-constraint-with-any-generic-type-definition – Nenad Mar 09 '13 at 11:58

1 Answers1

4

One common approach is to declare a non-generic base class. It won't give you strongly-typed access to the data of course, but you can potentially get a plain object version, and the name/description.

public abstract class DataTag
{
    public string Name { get; private set; }
    public string Description { get; private set; }
    public abstract object WeakValue { get; }
    public abstract object WeakRawValue { get; }
}

public abstract class DataTag<TRaw, TVal> : DataTag
{
    public abstract TVal Value { get; }
    public TRaw RawValue { get; set; }

    public override object WeakValue { get { return Value; } }
    public override object WeakRawValue { get { return RawValue; } }
}

Then your list is just an IEnumerable<DataTag>.

Notes:

  • I've given different names for the "weakly typed" properties. You could use Value and RawValue, then redeclare them (with new) in the generic type, but that's a pain in the neck in other ways. Avoid the naming collision if you can.
  • I've only provided a getter for WeakRawValue - you could provide a setter as well, and cast within the generic type, but that feels ugly to me. Heck, I would personally try to get rid of the setters entirely, and pass the values in as constructor arguments, making the type closer to immutable. (It's not going to be "properly" immutable if either of the generic type arguments is itself a mutable type, but it's better than nothing...)
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • This was the first solution that came in my mind. However i was looking for something different. – Vincenzo Mar 09 '13 at 11:59
  • 2
    @Vincenzo: If you've already come up with a solution and discarded it - presumably for some reason - it's helpful to say so when you write the question. I don't know of any better approach though. Why do you dislike this approach? – Jon Skeet Mar 09 '13 at 12:02
  • I was looking for a new solution (if any) to have a better way to manage this issue. However, your answer and proposed solution is very professional and a better one than the mine. Thank you. – Vincenzo Mar 09 '13 at 12:05
  • @JonSkeet Since I don't know if you could read my answer to your comment in my deleted answer, thank you for pointing out my error. – Matías Fidemraizer Mar 09 '13 at 12:51
  • @JonSkeet I am curious as to why you don't like the naming collision? I personally think it's more clear, as the property name (e.g. `Value`) is always the same when you go to access it, except that it is "appropriately typed" for what you have access to. Otherwise, when you use the property through a typed instance (`DataTag`), you see both `Value` and `WeakValue`, and `WeakValue` provides absolutely no value in this case and just clutters up IntelliSense. – jam40jeff Mar 11 '13 at 14:37
  • @JonSkeet I agree with jam...i would like to know better your opinion about. – Vincenzo Mar 13 '13 at 13:50