1

I've something along this lines:

public class Something
{
    private IDictionary<object,Activity> fCases;

    public IDictionary<object,Activity> Cases
    {
        get { return fCases; }
        set { fCases = value; }
    }
}

public sealed class Something<T> : Something 
{
    private IDictionary<T,Activity> fCases;

    public override IDictionary<T,Activity> Cases
    {
        get { return fCases; }
        set { fCases = value; }
    }
}

Note: override is not accepted on this case

Due to heavy Reflection usage there are situations where I've to downcast from Something<T> to Something but, I guess because Cases property is hidden, I'm losing Cases data.

How can I circumvent this situation? I've tried to use where T:object but that isn't accepted also.

EDIT: This is an example of why I need inheritance:

if (someVar is Something) {

    if (someVar.GetType().IsGenericType) 
    {
        // Construct AnotherObject<T> depending on the Something<T>'s generic argument
        Type typeArg = someVar.GetType().GetGenericArguments()[0],
            genericDefinition = typeof(AnotherObject<>),
            typeToConstruct = genericDefinition.makeGenericType(typeArgs);

        object newAnotherObject = Activator.CreateInstance(typeToConstruct);

        // Pass Something 'Cases' property to AnotherObject<T>
        constructedType.InvokeMember(
            "Cases",
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
            null,
            newActivity,
            new Object[] { someVar.Cases });
    }
}

But, because 'Cases' is hidden, it will be always null. Without inheritance I would have to write a BIG if-then-else with all the possible generic arguments. And, believe me, I do really have to use someVar is Something and Reflection to construct all this objects. This is a big generic API being converted to other big generic API and so they should not known each other and the conversion should be as transparent as possible.

Joao
  • 7,366
  • 4
  • 32
  • 48

4 Answers4

4

You won't be able to override it like that, and for good reason.

Imagine:

Something x = new Something<string>();
Button key = new Button();
x.Cases[key] = new Activity();

If your override worked, that would be trying to store a Button reference as a key in Dictionary<string, Activity>. That would be a Bad Thing.

Perhaps inheritance isn't actually appropriate in this case? If you could explain more about what you're trying to achieve, that would help. Perhaps you don't really need the dictionary as a property? Maybe just a method to fetch by key?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I've added an example of why I need inheritance. Can you please check it? – Joao Mar 03 '11 at 13:01
  • @Jota: You haven't really given an example of why you *need* inheritance. You've given an example of where you're currently trying to *use* inheritance. What bigger problem are you trying to solve? – Jon Skeet Mar 03 '11 at 13:05
  • @Jon-Skeet: I've to have Something on top of Something to be able to do _if (someVar is Something)_ otherwise I would have to have a big if-then-else with _if (somevar is Something) else if ... else if_ or can I do it through other process? – Joao Mar 03 '11 at 13:12
  • @Jota: Think at a higher level though - you haven't explained what `Something` is, or what you're trying to do. Why do you need to test this in the first place? Why are you trying to use reflection? **What's the bigger picture here?** – Jon Skeet Mar 03 '11 at 13:15
  • @Jon-Skeet: Ok, I'll try to explain it then. I'm building a Workflow Definition API that, at the end of the day, will be able to be executed using whatever Workflow Engine I might want to. In this case I'm writing the middle-ware that does the translation from my API to .NET WWF API to use CLR to run my workflows. My API relies heavily on generics and so WWF API. Moreover Something here is a Switch similar to WWF Switch<> but this is just a drop on a bigger ocean. Being able to resolve this without using Switch and only Switch would really be the correct way to do it anyway. – Joao Mar 03 '11 at 13:31
2

This is flat-out not going to work because the IDictionary<TKey, TValue> interface is invariant. An IDictionary<object, Activity> cannot be treated as an IDictionary<T, Activity>.

What you could do, rather than exposing an entire IDictionary<T, Activity> in your derived class, is simply delegate the calls you want to expose, like this:

public class Something
{
    protected IDictionary<object, Activity> Cases { get; set; }
}

public sealed class Something<T> : Something 
{
    public Activity GetCase(T key)
    {
        return Cases[key];
    }

    public void AddCase(T key, Activity case)
    {
        Cases.Add(key, case);
    }

    // etc. etc.
}

Alternatively, you could also define your own contravariant interface, something like:

interface IKeyedCollection<in TKey, TValue>
{
    TValue this[TKey key] { get; set; }
    void Add(TKey key, TValue value);
}

For the above interface, an IKeyedCollection<object, Activity> could act as an IKeyedCollection<T, Activity> because every T is an object.

Dan Tao
  • 125,917
  • 54
  • 300
  • 447
1

If you attempt to expose incompatible types at the different levels you're going to keep running into problems because at the end of the day you'll end up having to maintain 2 separate objects (or 1 custom object with 2 interfaces it can't completely satisfy).

These types are incompatible because there are values which can be added to IDictionary<object, Activity> which cannot be added to every instantiation of IDictionary<T, Activity>. Imagine for instance T is instatiated as string and the developer uses a int key elsewhere via Something. This creates a real problem for Something<string> implementations.

The way I would approach this is to change the base type Something to not expose a concrete type but instead to expose the relevant APIs.

public abstract class Something {
  public abstract IEnumerable<KeyValuePair> GetElements(); 
  public abstract bool TryGetValue(object key, out Activity value);
}

This gives Something<T> the flexbility it needs to properly sub-class Something and be very expressive about the types it wants to expose

public sealed class Something<T> : Something {
  private IDictionary<T,Activity> fCases;

  public override IDictionary<T,Activity> Cases
  {
    get { return fCases; }
    set { fCases = value; }
  }

  public override IEnumerable<KeyValuPair<object, Activity>> GetElements() {
    foreach (var cur in fCases) {
      yield return new KeyValuePair<object, Activity>(cur.Key, cur.Value);
    }
  }

  public override bool TryGetValue(object key, out Activity activity) {
    try {
      T typedKey = (T)key;
      return fCases.TryGetValue(typedKey, out activity);
    } catch (InvalidCastException) {
      activity = null;
      return false;
    }
  }
}

}

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • This is probably a way possible way to circumvent this problem. I've just added an example of why I need inheritance. Can you please just check it a give me your opinion? – Joao Mar 03 '11 at 13:02
1

During heavy reflection usage I also had the need to 'upcast' from generic types. I knew certain calls would be compatible, but I didn't know the types at compile time. If you look at it this way, it is not really 'upcasting' a generic type, but rather, allowing to use generics during reflection by generating the correct downcasts.

To this end I created a helper method to create delegates along the lines of Delegate.CreateDelegate, but allowing to create a less generic delegate. Downcasts are generated where necessary. I explain it in detail on my blog.

MethodInfo methodToCall = typeof( string ).GetMethod( "Compare" );
Func<object, object, int> unknownArgument
    = DelegateHelper.CreateDowncastingDelegate<Func<object, object, int>>(
          null, methodToCall );
unknownArgument( "test", "test" ); // Will return 0.
unknownArgument( "test", 1 ); // Will compile, but throw InvalidCastException.

A bit later I had a need to create entire less generic wrapper classes for generic classes, so that all method calls would immediately become available as less generic calls during reflection. This might or might not be useful in your scenario as well. For this purpose I created a (not as thoroughly tested) method which allows to generate this wrapper class at runtime using emit. It is available in my open source library. I haven't written about this yet, so when interested you'll just have to try it out (and possibly see it fail since it's still quite new).

Steven Jeuris
  • 18,274
  • 9
  • 70
  • 161