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
Can You Configure Log4Net in Code Instead of Using a Config File
Display a Image in a Console Application
How to Change Time in Datetime
C# Pattern to Prevent an Event Handler Hooked Twice
Convert Word Doc and Docx Format to PDF in .Net Core Without Microsoft.Office.Interop
Wpf Mvvm Why Use Contentcontrol + Datatemplate Views Rather Than Straight Xaml Window Views
Mongodb Gridfs with C#, How to Store Files Such as Images
How to Set the Wix Installer Version to the Current Build Version
Write to Windows Application Event Log Without Event Source Registration
Converting File into Base64String and Back Again
How to Get the Directory from a File's Full Path
Passing an Enum Value as Command Parameter from Xaml
Why Are Subjects Not Recommended in .Net Reactive Extensions
Performing Inserts and Updates with Dapper
Additional Text Encountered After Finished Reading JSON Content:
Does Distinct() Method Keep Original Ordering of Sequence Intact