views:

220

answers:

2

I must honestly say that I do not really understand much about casting, but I thought this would work.

I have a Generic Class Test:

public class Test<T,U>
{
     T variable1;
     U variable2;

     //etc.
}

I need to use this class in a WPF view, and since you can't create generic views in WPF (how lovely) I thought: lets just use a Test<object, object> for the view, since I am only concerned about working with the string representations of the variables in the view.

So I try:

  Test<Foo, Bar> test = new Test<Foo, Bar>();
  return test as Test<object, object>;

But that gives me:

  Error 1   Cannot convert type 'DomainModel.Tests.Test<T,U>' 
  to 'DomainModel.Tests.Test<object,object>' via a reference conversion, boxing
  conversion, unboxing conversion, wrapping conversion, or null type conversion

I would think that every object must be castable to object?

Anyhow, I am quite stuck now in how to ever use generic classes in WPF...

Any pointer in the right direction?

+2  A: 

C# up to version 3.0 does not support generic co/contra-variance. That is, something like IEnumerable<string> is not compatible with IEnumerable<object>.

C# 4 introduces statically checked definition site safe generic co/contra-variance but it's not going to help you either. It requires the generic parameter to be used only in input or output positions, but not both. That is, List<string> is not going to be compatible with List<object> in C# 4.0, but IEnumerable<string> can be used as an IEnumerable<object> since the type parameter for IEnumerable is only used as the return value (an output position) of the Current property.

Mehrdad Afshari
+3  A: 

This is a generic variance issue. C# 3 does not allow variance in generic parameter types: thus, IEnumerable<string> is not compatible with IEnumerable<object>. This restriction will be relaxed for safe scenarios in C# 4. But this won't help for your case because C# 4 only supports variance on interfaces or delegates. And even if a future version of C# allows generic variance on classes, it still may not help you because it's not clear that Test<object, object> is a safe cast: suppose variable1 has a setter:

Test<string, string> t = new Test<string, string>();
Test<object, object> bad_t = t as Test<object, object>;
bad_t.variable1 = new Llama();  // but variable1 should contain only strings!

You can however "cast" a Test<string, string> to object:

object good_t = t;  // don't even need a cast

WPF bindings will still then be able to access its properties via reflection.

Alternatively, define a non-generic interface that provides the functionality you need (in your case "the string representations of the variables"):

public interface IPresentV1AndV2  // stupid name of course
{
  public string Variable1AsString { get; }
  public string Variable2AsString { get; }
}

and implement this on your generic class. You can then access the stringised values via the interface members. (Obviously this particular interface example is stupidly bound to the implementation and in reality you would give it a name and members that reflected the business meaning of the data it exposes.)

itowlson
Variance in C# 4 will only work on interfaces and delegates, so whether it is safe or not is irrelevant in this case; "Test" is a class, not an interface or delegate.
Eric Lippert
Thanks, Eric; updated.
itowlson