Explicitly Cast Generic Type Parameters to Any Interface

Explicitly cast from generic type to an object of its type parameter

If you spell out the types explicitly, the problem becomes obvious:

public void ConversionTest()
{
Personperson = new Person { FirstName = "Bob", LastName = "Smith" };

IValidatable validatable = Validatable.AsValidatable(person);

Person cast = (Person)validatable; // FAILS here with InvalidCastException
}

Since validatable has the interface type, the conversion operator (declared in the Validatable<T>) cannot be applied.

Nullable<T> has special runtime support to enable this scenario.

Why can't I cast an item to a generic type — where the generic type is an interface, and after checking that the item implements said interface?

Here you go:

   if (effect is T typed) {
effects.Add(typed);
}

As for why: you'd need an object cast in the middle: (T)(object)effect

Cast object to generic interface

What you're asking for isn't possible. It doesn't make sense to refer to a Parent<MyObject1> as a Parent<object>. If you have a string, you can't pass it to a method whose signature is DoSomething(MyObject1). You need to find another way to do what you're trying to do.

Usage of generic type for explicit conversion

Why do you need to cast to object first?

_internalObject is of type MyInternalClass, and you are trying to cast this to T. T can be any type, so the compiler thought, "I'm pretty sure you certainly can't cast MyInternalClass to any type.". If you cast it to object first, then the compiler thinks "this value of type object can be any type at runtime, so it can be casted to any type."

Here's another explanation using the spec if you are not satisfied.

According to the C# spec, section 6.2.7, "Explicit conversions involving type parameters":

Explicit reference conversions

The following explicit conversions exist for a given type parameter T:

  • From the effective base class C of T to T and from any base class of C to T. At run-time, if T is a value type, the conversion is executed as an unboxing conversion. Otherwise, the conversion is executed as an explicit reference conversion or identity conversion.
  • From any interface type to T. At run-time, if T is a value type, the conversion is executed as an unboxing conversion. Otherwise, the conversion is executed as an explicit reference conversion or identity conversion.
  • ...

The effective base class of T is object, which is why you can do this cast.


That said, what you are doing here seems like a bad idea. This code is very type unsafe. You can pass any type into T, but only things like object, IMyInternalClass and MyInternalClass works for T.

Therefore, this seems like a misuse of generics. You should just return a MyInternalClass or IMyInternalClass:

public MyInternalClass GetInternalObject()
{
return _internalObject;
}
// or
public IMyInternalClass GetInternalObject()
{
return _internalObject;
}

Why can't I cast a more derived generic type to a less derived generic type?

Consider we introduce messages and listeners for creating employees:

public class CreateMessage : IMessage {
public int EmployeeId { get; set; }
}

public class CreateEmployeeListener : IListener<CreateMessage> {
public void ProcessMessage(CreateMessage message) {
}
}

// Later...
var listener = (IListener<IMessage>) new DeleteEmployeeListener();
IMessage createMessage = new CreateMessage();
listener.ProcessMessage(createMessage); // What happens here?

Although createMessage is an IMessage, DeleteEmployeeListener can't handle a CreateMessage.

In the case of your Ilistener interface, the generic type is contravariant, meaning the "input" types are generic. This means you can pass a more specific type, but not less.

More info here: https://learn.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance

Cast unknown object to generic interface of interface (from initially explicit generic type of generic collection type of type)

If you define your Car class with ICollection instead of List<CarPart>, then works:

public class Car : IHasParts<ICollection>
{
public ICollection Parts { get; set; }
}

You can still initialize your Parts with a List<CarPart>

Why there is a restriction for explicit casting a generic to a class type but there is no restriction for casting a generic to an interface type?

That's exactly what you get in normal circumstances - without generics - when you try to cast between classes with no inheritance relationship:

 public interface IA
{
}

public class B
{
}

public class C
{
}

public void SomeMethod( B b )
{
IA o1 = (IA) b; <-- will compile
C o2 = (C)b; <-- won't compile
}

So without a constraint, the generic class will behave as if there is no relationship between the classes.

Continued...

Well, let's say someone does this:

 public class D : B, IA
{
}

And then calls:

SomeMethod( new D() );

Now you'll see why the compiler lets the interface cast pass. It really can't know at compile time if an interface is implemented or not.

Remember that the D class may very well be written by someone who is using your assembly - years after you compiled it. So there is no chance that the compiler can refuse to compile it. It must be checked at run time.

C# casting an inherited Generic interface

The problem is the generic type parameter. If you make the interface parameter covariant then the cast will work.

This is accomplished by adding the out keyword, like so:

interface IPresenter<out V> where V : IView
{
void PresBlah();

}

You can learn more about how this works with the following MSDN article: Covariance and Contravariance in Generics. The section Generic Interfaces with Covariant Type Parameters specifically applies to your question.

Update: Make sure you check the comments between @phoog and me. If your actual code accepts a V as an input, you will be unable to make it covariant. The referenced article and @phoog's answer explains this case in further detail.



Related Topics



Leave a reply



Submit