-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generic expression of a derived type cannot be handled by a pattern #16195
Comments
That's interesting. If I had to guess type-switch pattern matching might be disabled on generic variables due to having to emit IL that would support both value and reference types. However, in this case at least, |
Oddly enough, it works with constrained generic types, public class C
{
public void Send<T, U>(T packet)
/* where U : class */
where T : /* class, */ U
{
if (packet is U keepalive)
{
// Do stuff with keepalive
}
switch (packet)
{
case U keepalivePacket:
// Do stuff with keepalivePacket
break;
}
}
} Uncommenting class constraint on either generic types only causes a different code to be generated, but it compiles anyways. |
Looks like a bug. |
The reason it doesn’t work is that there is no conversion (explicit or implicit) defined from var keepalive = (KeepalivePacket)packet; // error: Cannot convert type ‘T’ to ‘KeepalivePacket’ However, the compiler does allow the following to compile (because there is no requirement that a conversion exists), and in fact it can return true: var isKeepAlive = packet is KeepalivePacket; It seems strange to me that the language specification is defined such that no (explicit) conversion exists here. We'll look at what we can do about that. |
Possible approach for fixing dotnet#16195
We're not going to do anything about this in C# 7. You'll have to add a cast to your code to work around it. if ((Packet)packet is KeepalivePacket keepalive)
{
// Do stuff with keepalive
}
switch ((Packet)packet)
{
case KeepalivePacket keepalivePacket:
// Do stuff with keepalivePacket
break;
} Once we have recursive patterns, this may be more difficult to work around. Moreover, the awkward language rule that underlies this issue (i.e. that there is no conversion from |
The "as type" operator has special dispensation for open types. Applying that same dispensation to the "is pattern" operator may make this work.
|
@gafter Did you find a design note or something about this? It's quite surprising that |
Having the same problem, different code. Visual Studio tells me it can be simplified and simplifies it for me, but I get the error as well. |
…ameters. Fixes dotnet#16195 This is a language change for 7.1. See dotnet/csharplang#154. Some tests may fail until dotnet#18756 is integrated.
@gafter so this fix will be in C# 7.1? But how the update of the compiler work? We will get an update of VS2017? |
@fanol Yes, we're hoping to include this feature with C# 7.1, which we expect to ship as an update of VS2017. |
…ameters. (#18784) Fixes #16195 This is a language change for 7.1. See dotnet/csharplang#154.
If it takes longer to fix this, please update the analyzer to not suggest using pattern matching in this case. |
This seems to be an issue even for some non-generic types. I had an interface defined which I implemented on certain exceptions:
Then I passed the interface to a method and tested it against two exception types:
In the doesntCompile line, the message was CS8121, an expression of type 'IAcceptablePrimitiveException' cannot be handled by a pattern of type 'TargetInvocationException'. It certainly seems weird that the interface expression can be handled by a target of type AggregateException but not one of of type TargetInvocationException. In the doesCompile line, a warning CS0184 is generated saying the expression is never of type TargetInvocationException. |
Version Used:
Microsoft Visual Studio Professional 2017 RC
Version 15.0.26014.0 D15REL
Microsoft .NET Framework
Version 4.6.01586
Visual C# Compiler version 2.0.0.61213
Steps to Reproduce:
I get a compilation error for both the if statement and case statement.
The code compiles successfully if the type is not a derived type of
Packet
(ie.packet is Packet keepalive
orpacket is object keepalive
works fine).The code compiles without error if I first cast the parameter to
object
.I couldn't find any mention of unsupported pattern matching with generic parameters/variables in the design notes/blog posts.
Is this expected to fail? Does this compilation error need a more informative message?
Roslyn is recommending pattern matching for the following code with IDE0019. Applying the code fix to the following code results in the compilation error above.
Does IDE0019 need to be updated to not apply when the variable/parameter is generic?
The text was updated successfully, but these errors were encountered: