Roslyn: C# dynamic behaviour in ternary operators

Created on 17 Sep 2016  Â·  27Comments  Â·  Source: dotnet/roslyn

Version Used: any version since dynamic was introduced in .NET 4.0 (tested with VS 2012 & 2015).

Steps to Reproduce:

  1. Declare a dynamic variable.
  2. Include it in a ternary operator together with other-type variable (make sure that there is a type conflict).
  3. See how any type error is plainly ignored.

Sample code:

private static double Test1()
{
    dynamic stringVal = "";

    //Working as expected. 
    //The type of the dynamic variable shouldn't be checked.
    return stringVal;
}

private static double Test2()
{
    dynamic stringVal = "";

    //Not working as expected. 
    //This code shouldn't compile because it includes an unfixable error.
    return
    (
        true ? stringVal : "string2"
    );
} 

Expected Behavior: the ternary operator should account for the most restrictive type (string in the Test2() case) and, consequently, this code shouldn't compile (i.e., either because stringVal type isn't string, against what the ternary operator expects; or because the ternary operator returns a string type, against what the return statement expects). The fact of a priori not knowing the exact reason for the error isn't relevant here as far as it will certainly occur (what the compiler could easily understand in case of relying on the aforementioned giving-preference-to-the-most-restrictive-alternative approach).

Actual Behavior: dynamic variables are being taken as absolute references in ternary operators (perhaps in other situations too) what avoids the compiler to see any problem in these cases. That is, a code with a ternary operator including a dynamic variable will always compile, independently upon any internal/external type incompatibility. Such a reality shouldn't occur on account of the dynamic scope (i.e., only affecting the behaviour of the variables declared as dynamic).

Area-Language Design Discussion

Most helpful comment

As explained, the most logical approach is giving preference to the most restrictive alternative

That is the opposite of the most logical approach. The ternary operator gives preference to the _least_ restrictive alternative. For example, if the values are of types object and string, the result is of type object, not string. The type dynamic is not a special case here.

All 27 comments

Fairly sure this is by design. Ternary expressions can only have a single type, and since you used a dynamic as one of the operands that renders the type of the entire expression as dynamic. The "string2" is then implicitly cast to dynamic within that expression and the binder is attempting to convert that to double. Effectively the compiler is doing this:

dynamic stringVal = "";
dynamic $temp;
if (condition) {
    $temp = stringVal;
}
else {
    $temp = "string2";
}
double $retval = $temp;
return $retval;

@HaloFour Yes, I know that this is by design. That's why I consider it a design flaw.

As explained, the most logical approach is giving preference to the most restrictive alternative (string in this case). If we have a string and a can-be-anything, there are two possible scenarios:

  • Scenario 1, the can-be-anything is not a string; a DateTime, for example. We have string-DateTime.
  • Scenario 2, the can-be-anything is a string. We have string-string.

Scenario 1 would crash because a ternary operator cannot deal with two different types, but the compiler wouldn't warn about it. This isn't a problem because of being precisely the whole point of dynamic (not knowing the type at compilation).

On the other hand, the output of such a ternary operator is certain without having to check the dynamic variable type: either a string or an error (which happens at compilation; thus, from the compiler point of view, there is only one option: string). As far as the proposed function expects a double, this code shouldn't compile.

Even you can see the problem from a different perspective. By replacing dynamic with object, you have the following non-compilable code:

private static double Test22()
{
    object stringVal2 = "";

    //Working as expected. It doesn't compile. 
    return
    (
        true ? stringVal2 : "string2"
    );
} 

Logically, object and dynamic are different. But the question is why dynamic can affect more than just the dynamic variable itself? I accept that the type of stringVal2 is known and the one of stringVal is not (also accept that, in case of assigning a wrong type to stringVal, I would get a runtime error). But why stringVal is also affecting how the compiler deals with the ternary operator? Why you can have two variables with exactly the same value & type, one of them being compilable and the other one not? And even more important: why not relying on the really easy and pretty logical proceeding of giving preference to the most restrictive option (i.e., string in this case) and avoiding any problem?

I want also to highlight that firstly wrote this issue in CoreFX (https://github.com/dotnet/corefx/issues/11825), where I included more ideas which some people might want to look at. Here I made it briefer to meet the issue-template requirements.

Scenario 1 would crash because a ternary operator cannot deal with two different types

Are you talking about something like this?

``` c#
private static double Test()
{
dynamic doubleVal = 3.14;

return true ? doubleVal : "string";

}

Because that does not crash. The ternary operator cannot deal with two incompatible types, but that's not the case here. Here, you have `dynamic` and something implicitly convertible to `dynamic`, so the ternary operator works fine.

> On the other hand, the output of such a ternary operator is certain without having to check the `dynamic` variable type: either a `string` or an error.

I don't think it is certain. Even if there is no implicit conversion at compile time, there could be one at runtime. Either because the it's actually a different type (e.g. with `(Base)new Derived()`, the compiler sees that the compile-time type is `Base`, but at runtime it will be `Derived`, if `Derived` has implicit conversion and `Base` does, this would make a difference), or because the type changed (e.g. `string` added an implicit conversion to `double` and you upgraded to the new version of `string`, but did not recompile).

> By replacing `dynamic` with `object`, you have the following non-compilable code

That code fails with:

> CS0266 Cannot implicitly convert type 'object' to 'double'. An explicit conversion exists (are you missing a cast?)

That error explains exactly why the `dynamic` code compiles: there is an implicit conversion from `dynamic` to `double`. So, just like this code with explicit conversion from `object` compiles (and then throws at runtime):

``` c#
private static double Test()
{
    object stringVal2 = "";

    return (double)(true ? stringVal2 : "string2");
}

so should the dynamic code with implicit conversion from dynamic compile.


In short: the whole point of dynamic is to make type-related decisions at runtime, instead of compile time. Trying to make more decisions at compile-time for it does not make much sense and has to be considered very carefully.

@svick Thanks for the correction, I did chose a bad example (updated my post). But here you have an even more curious issue:

private static double Test3()
{
    double doubleVal2 = 0.0;

    //Doesn't compile.
    return true ? doubleVal2 : "string";
}

Your code (with a dynamic variable) runs fine, but this one doesn't even compile (the kind of behaviour which seems logical to me when dealing with the ternary operator)?! How can be this the case? A variable which can be any type works fine when being a specific case (double); but a variable actually having such a type doesn't even compile?!

This is starting to become a bit too weird. And all this might have been avoided with the aforementioned suggestion of preferring the most restricted alternative! (As almost every time when dealing with complex realities, keeping it simple is the solution :)).

@varocarbas The ternary operator chooses one of the two types, as long as there is an implicit conversion from the other type. So:

  • if you have double and dynamic, it chooses dynamic, because there is an implicit conversion from double to dynamic
  • if you have double and object, it chooses object, because there is an implicit conversion from double to object
  • if you have double and string, it fails to compile, because there is no implicit conversion between double and string

And all this might have been avoided with the aforementioned suggestion of preferring the most restricted alternative!

Consider this code:

``` c#
private static dynamic Test()
{
dynamic doubleVal = 0.0;

return true ? dynamicVal : "string";

}
```

Are you saying that the type of the ternary expression here should be string? And so this code should fail at runtime? That's not what I would expect and I also don't see how would that solve anything. Or did I misunderstood what you meant?

@svick You did understand perfectly what I meant. But I think that we have different ideas on this front. Let me do a quick overview to synchronise.

My understanding of how types work (and my expectations on this front) is based upon the native ones (in its widest sense, plainly as opposed to dynamic, object or similar). I expect any other "supra-type", like object or dynamic, to basically follow the same rules. That is, if I see that (true ? doubleVar : stringVar) cannot compile (logical on account of the fact that two different types cannot be compared between each other); then, I expect the following:

dynamic dynamicDoubleVar = doubleVar;
(true ? dynamicDoubleVar : stringVar); // Shouldn't compile.

object objectDoubleVar = doubleVar;
(true ? objectDoubleVar : stringVar); // Shouldn't compile.

This is what I call consistency (intuitiveness, the most logical thing, etc.). I expect differences in the object and dynamic variables, but only in case of affecting to themselves (e.g., conversion from/to native types). After the conversion to the given native type has been performed, I expect them to behave identically (or, at least, similarly enough) to what the given native type would do. Quite a few of the samples in this thread show that dynamic variables don't follow these rules and do behave differently than the corresponding native type (even with "external effects", by redefining how to analyse a ternary operator/determine what compilable is).

With "more restrictive alternative" I meant applying the (kind of) general rule of always chosing the narrowest applicability. In the ternary operator, if you can choose between anything and string, choose string (because you have to choose something; a type has to be returned); assume that the dynamic variable is a string and perform all the subsequent actions accordingly. I proposed this by applying the aforementioned ideas of extending what works for native types. If you want to create a new categorisation as the one that you are including in your last post (where dynamic/object are considered independent entities, rather than representations of the corresponding native types; bear in mind that, for me, dynamic converted to double should behave like double), my suggestion wouldn't hold.

I do expect any ternary operator formed by two different types (e.g., double-string or dynamic_double-string) to not compile. I also expect a ternary operator to return the type in which the dynamic variable has been converted (not just dynamic, which has no meaning and a huge scope). I expect to use dynamic (or, eventually, object) as a perfectly-controlled way to avoid expressly telling the type; but this variable should also behave identically (almost; logically, all the direct type checks will be ignored) as any other variable of that type. I also expect a consistent framework where different alternatives always output identical results. That's why I consider this implementation to be faulty.

dynamic isn't a "supra-type", it's your explicit declaration to the compiler that it should disable type checking and to "figure it out" at runtime.

I expect to use dynamic as a perfectly-controlled way to avoid expressly telling the type

This might be where your confusion is. dynamic is not "I'm not going to tell you the type, figure it out", that's what var is for (and there are good reasons why it's so limited).

Instead dynamic is "at compile time, assume that this value could be any type and figure out what to do at runtime".

@HaloFour Nothing is a "supra-type", this is a word I made up to explain my ideas. I meant explicitly declaring a given type (double, string or whatever) vs. doing it indirectly. The whole point of my posts was highlighting that a dynamic variable assigned to a double one should behave identically than a variable originally defined as double (except, logically, for the dynamic peculiarities of no type check).

Or, in other words, you shouldn't be able to reach certain scenario (e.g., a ternary operator being compilable) by using one alternative and not being able to do so by using a different approach which, on the paper, is identical (variable with same type and value).

@svick I am perfectly aware about the differences between var and dynamic. Sorry if I have provoked some misunderstanding while trying to make my explanations more clear.

I am not confused at all. I know perfectly what dynamic (or var or object or any other thing) can deliver. I do understand what seems to be the logic behind the current implementation. I plainly don't agree with it, because of considering this behaviour inconsistent with the remaining parts (+ even with the a priori most logical output: why affecting anything else than just the variable defined as dynamic?). For me, you (and @HaloFour) are the ones being confused here, because you aren't trying to understand my point (not even my intention); you just want to convince me about how things have to be (by also trying to justify the validity of anything); not agreeing with you is interpreted as "you don't understand" (what can I say about that?). No, I am afraid that you are the ones not understanding here (neither interested in doing so).

In any case, I will stop over-explaining a point which, in my opinion, was crystal clear since my first post (reading the original CoreFX post might also be helpful). I don't want to convince you or anyone else about anything; neither to start a faith war about what is, should be, will be (quite bad past experiences on this front). The whole point of my post was highlighting an issue which is quite evident to me (I was completely focused on a pretty complex development; by using dynamic in a relevant way for almost the first time; and I only needed to see this behaviour once to know that something wasn't right). I shared my impressions by assuming that they might be useful to more people (= others thinking like me); by expecting an objective-correction-prone discussion, rather than a blind repetition of how things have to be (and people thinking otherwise being wrong or bad or enemies or trolls or whatever; sorry, but as said, I had quite bad past experiences with this community). If the .NET community/team thinks different than me, I would accept it and move on.

I understand your use-case, but believe that current behavior is very reasonable.

It really comes down to 2 principles. You can probably find them phrased better in some older Eric Lippert's posts, but roughly:

  • dynamic statically behaves like type that has every method and property and is implicitly convertible to and from every type.
  • When deciding type of expression, only types that appear in that expr are considered as candidates. If there is exactly one candidate that all others can implicitly convert to chose that one, otherwise its an error.

Like so many C# features, both strike fine balance in simplicity, power and safety (my opinion). Adding special casing for their interaction would make a lot of harm. For the price of some safety, it would remove expresivity and add a lot of complexity to the language.

@zippec It is a bit difficult to argue against an E. Lippert quote (good argumentation technique, by the way ;)). In any case and without daring to think that my knowledge is better than his, the "one candidate that all others can implicitly convert to chose that one, otherwise its an error" part doesn't sound too good to me. In fact, it doesn't even seem applicable to this ternary operator case (other than for dynamic). For example, it doesn't apply to object (which does show the behaviour which I expect).

Objectvariables (or var or any other not-expressly-typed variable), after being converted to another type, behave like this other type. Bear in mind that all these variables are meant to be converted to something; they have to be assigned before being used in the ternary operator (dynamic variables too). So the question is: why the dynamic variable wants to remain dynamic (= unassigned) even after an assignation did occur? And why no other variable can do such a thing?

What is much, much more important: how can be a so irregular behaviour be supported after seeing the inconsistent consequences (as shown in various samples in this thread)? If you have a ternary operator including a string, it has to output a string or an error (no need to check the other member). This is true in each single scenario, except when dynamic is present (?!). Because apparently and unlikely in any other case, the ternary operator assumes that the type is dynamic (?!), rather than string.

The reason why I created this issue was that, while writing a code including dynamic variables, I did a mistake similar to the one described in my first sample; a mistake which I could never do (VS not letting me compile) in any other situation. Such a scenario is so different to what C# usually delivers that I wouldn't have ever expected it to happen. Imagine that I didn't see the bug and did continue writing code. When debugging it at a later stage, I would never have looked at something like this: code compiling despite having a faulty ternary operator?! Should I stop trusting Visual Studio recognition capabilities? And/or be afraid of each new extension because of perhaps provoking a redefinition of the rules which have always been applicable to anything else?

A ternary operator (and perhaps other things; as said, this behaviour might also be occurring in other scenarios) behaves always in the same way (e.g., if it includes a string and the expected value is a double, it shouldn't compile). You cannot bring a special element making it behave differently. This is the point which I am trying to make and which some of the last comments seem to be losing: it is not about the dynamic variable itself, it is about how it affects an external element (i.e., the ternary operator). How can it do that and why it is the only element which can do such a thing? My opinion: a mistake. The solution: make sure that the ternary operator (or anything else) behaves as usual by adapting dynamic to it, not the other way around.

As explained, the most logical approach is giving preference to the most restrictive alternative

That is the opposite of the most logical approach. The ternary operator gives preference to the _least_ restrictive alternative. For example, if the values are of types object and string, the result is of type object, not string. The type dynamic is not a special case here.

If you have a ternary operator including a string, it has to output a string or an error (no need to check the other member). This is true in each single scenario, except when dynamic is present (?!).

It's also true for object:

``` c#
object o = 42;
var x = condition ? o : "foo"; // the type of x is object, the value of x is either 42 or "foo"

And it's also true for types that have implicit conversion from `string`, like `XNamespace`:

``` c#
XNamespace ns = "ns";
var x = condition ? ns : "s"; // the type of x is XNamespace, the value of x is XNamespace with NamespaceName of "ns" or "s"

The reason why I created this issue was that, while writing a code including dynamic variables, I did a mistake similar to the one described in my first sample; a mistake which I could never do (VS not letting me compile) in any other situation. Such a scenario is so different to what C# usually delivers that I wouldn't have ever expected it to happen. Imagine that I didn't see the bug and did continue writing code. When debugging it at a later stage, I would never have looked at something like this: code compiling despite having a faulty ternary operator?! Should I stop trusting Visual Studio recognition capabilities? And/or be afraid of each new extension because of perhaps provoking a redefinition of the rules which have always been applicable to anything else?

The whole point of dynamic is to disable static type checking. If you want to make sure VS finds most of your type errors, _don't use dynamic_.

The solution: make sure that the ternary operator (or anything else) behaves as usual by adapting dynamic to it, not the other way around.

It already does. If you look at the specification for the ternary operator, you won't see any special rules for dynamic.

@gafter Perhaps I didn't phrased my point properly. The idea I was trying to transmit was that if you have one-type vs. any-type, you should choose one-type (because choosing any-type would make the condition always true). I meant when the ternary operator is determining whether the same-type condition holds (and consequently the code is compilable) or not.

@svick As written above to gafter, perhaps I didn't phrased my point properly. I don't have any problem with the returned type, but with what the ternary operator does while comparing types (and a dynamic variable is involved). The problem seems to be that the compiler skips any type check involving a dynamic variable by ignoring that, in some cases (like in the ternary operator), knowing the type of the surrounding variables is enough.

If I have a compilable ternary operator (even though it might crash at runtime because of the dynamic peculiarities), I wouldn't see any problem in returning a dynamic variable (logically, assigned to whatever type is applicable). The problem I am highlighting is that the fact of having a dynamic variable converts a non-compilable ternary operator into compilable.

For example: (true ? dynamicVar : stringVar) is fine when expecting a string (and it might return a dynamic variable). The problem is that this ternary operator also compiles in case of expecting a double or a DateTime or whatever. That is: just the fact of having a dynamic variable has changed the way in which the compiler treats the ternary operator?! It doesn't even analyse stringVar and confirms that no compilation is possible.

Regarding your

The whole point of dynamic is to disable static type checking. If you want to make sure VS finds most of your type errors, don't use dynamic.

You are again not getting the point: my problem isn't the behaviour of the dynamic variable per se. I accept the consequences and the errors which choosing the wrong type might provoke. The problem is that this variable makes the ternary operator (and perhaps other situations too) to behave differently than in any other scenario. In fact, the mistake of the referred code wasn't the dynamic variable, but the string one!! VS would have complained in any other case, but when I put a dynamic variable there it plainly doesn't say anything.

@gafter Re-clarifying my point. I meant comparing the expected type with the one returned by the ternary operator (assumed to be the most restricted one, string in my example). That is, if you have a ternary operator with one string, you should check the expected type vs. this string (because the other element has also to be a string). After confirming that everything is OK (expected type matches what the ternary operator can deliver), you might then make further considerations (what you and @svick were referring about preferring dynamic, then object, etc.). In fact, this kind of check is already being performed when dealing with object which, as shown, doesn't allow a code on these lines to compile.

That's why I prefer to include descriptive enough examples, rather than likely to be over-complicated/confusing clarifications (+ small details being misinterpreted, etc.). My first code shows this point very clearly: you have a ternary operator including a string variable when a double is expected. This situation is non-compilable independently upon what the other member is. Even by bringing the dynamic essence to its pure limits, this situation shouldn't compile (the dynamic variable being anything other than a string should be an error/non-compilable).

I have realised that dynamic variables also allow non-compilable methods to compile, as shown in the code below.

``` C#
private static void CallingMethod()
{
DateTime dateVar = ReturnString(""); //It doesn't compile.

dynamic dynamicVar = "";
dateVar = ReturnString(dynamicVar); //Now it compiles.

}

private static string ReturnString(string arg)
{
return arg;
}
```

I found the first sample already quite descriptive, but this one seems even clearer.

@varocarbas Reproduced. http://csharppad.com/gist/4555adee9cbd59949020fb91be849279
That doesn't looks like it should have compiled.

@tenor
I see this behaviour in VS 2012 & 2015. To not mention that it is quite compatible with the first sample I included here (i.e., not too weird/non-expectable).

Apparently, this web-app you are using isn't too reliable (first time I use it), but I was able to make it work as per my description anyway. You didn't copy my whole code, but let the CallingMethod() contents outside. Just copy all the code as it is, with two methods and you should be able to reproduce the described behaviour: an error with DateTime dateVar = ReturnString(""); and compiling fine when only dynamic dynamicVar = ""; DateTime dateVar = ReturnString(dynamicVar); is present.

Apparently, this web-app you are using isn't too reliable (first time I use it),

:smile: Looks like MS needs to market C# Script mode a bit more. I wrote the app. Please drop me a line off-forum on what was confusing.

The issue I see here is that the the dynamic argument is contagious enough to prevent the compiler from checking if the return type of the ReturnString method can be received by the dateVar variable.
The code will _always_ fail at runtime so I think you're right. The compiler should detect it.

@tenor

I wrote the app

Ups! Sorry. I meant that, logically, it isn't like using Visual Studio. For example, it isn't clear what is in there when you start writing (I guess that a class inside namespace?) and the errors are logically not as descriptive. I didn't get a bad impression of it (it seems easy to use and quite quick); but I do certainly prefer VS. In any case, I guess that it can be useful for people without VS.

The compiler should detect it.

I think so. That's why I started this issue. I am currently writing a quite big code with lots of dynamic variables.

From the spec section 7.5.4.

Compile-time checking of dynamic overload resolution
For most dynamically bound operations the set of possible candidates for resolution is unknown at compile-time. In certain cases, however the candidate set is known at compile-time:
• Static method calls with dynamic arguments
• Instance method calls where the receiver is not a dynamic expression
• Indexer calls where the receiver is not a dynamic expression
• Constructor calls with dynamic arguments
In these cases a limited compile-time check is performed for each candidate to see if any of them could possibly apply at run-time.This check consists of the following steps:
• Partial type inference: Any type argument that does not depend directly or indirectly on an argument of type dynamic is inferred using the rules of §7.5.2. The remaining type arguments are unknown.
• Partial applicability check: Applicability is checked according to §7.5.3.1, but ignoring parameters whose types are unknown.
If no candidate passes this test, a compile-time error occurs.

@varocarbas
If I'm interpreting this correctly, the spec says the code is fine because the proper overload is unknowable at compile time, however in some cases, the candidate overloads can be determined at compile time in certain scenarios. The code you supplied matches the first scenario. (static method call with dynamic arguments).

@tenor

If I'm interpreting this correctly,

No, you are certainly not. You are talking about a scenario which isn't even present in this sample (there is no various overloads to choose from, just one).

I don't see the point of continuing with this discussion. My example is very clear and the underlying ideas (i.e., dynamic variable just passed as an argument provoking the method to behave differently than what would have happened by passing any other variable; and an impossible-to-be-run-and-consequently-not-compilable code to compile) should be clear to anyone.

Note that I am trying to be nice (promised it to the .NET team); and this is actually the only reason why I answered your first two messages as I did (otherwise, my first answer would have been completely different because of thinking that being nice would have plainly provoked everyone to waste their time). Feel free to continue discussing with others, but please involve me in the discussion only when sharing relevant points (ideally supported with descriptive examples, because abstract ideas are an easy way to lose track).

Hopefully, you will be not feel bothered by this somehow-clear-but-still-pretty-soft answer :)

@varocarbas I was trying to say that the spec backs your claim.
There could be potential overloads in a derived type in a different assembly that the compiler is unaware of. That's why the compiler allows the code.
However, the spec is saying that for calls to static methods (like in the example you provided), there will be no derived types and so the compiler should be able to catch the error.

@tenor

I have some problems to see the compatibility between your original "the spec says the code is fine" and "the spec backs your claim", because I understand that the code I posted was wrong (= the compiler thinks differently than what I expect). But this is precisely the problem with abstract, without-code-sample talking and why I don't want to continue this conversation (IMHO, a pointless waste of time).

There could be potential overloads

Logically, but you were using this text to refer to a scenario where only one overload was present. Do you want to consider multiple overloads? Excellent! Show a code or explain how the described behaviour works under such conditions. But using a given spec to justify/criticise a completely different situation doesn't seem too correct.

That's why the compiler allows the code

Again no. This is a 1-overload scenario, the multiple-overload rules don't apply here. Your spec is applied when determining which overload, out of various ones, should be used. Here there is no possible confusion; just one overload, no doubt about which one to use.

The following code does illustrate a multi-overload scenario:

``` C#
private static void CallingMethod()
{
//DateTime dateVar = ReturnString(""); //It doesn't compile.

dynamic dynamicVar = new DateTime(); // "";
DateTime dateVar = ReturnString(dynamicVar); //Now it compiles.

}

private static string ReturnString(string arg)
{
return arg;
}

private static string ReturnString(DateTime arg)
{
return arg.ToString();
}
```

If you test this code, you would see that there is no confusion here either: dynamic dynamicVar = new DateTime(); provokes ReturnString(DateTime arg) to be selected; and dynamic dynamicVar = ""; ReturnString(string arg). There is an error because of trying to store a string in a DateTime variable, but the overload-selection part works fine. Again this code shouldn't compile (because both methods return a string rather than the expected DateTime variable) and again it does. So the number of overloads doesn't seem to be an issue here; but you are free to go deeper into all this by considering more complex situations.

calls to static methods (like in the example you provided), there will be no derived types and so the compiler should be able to catch the error

I am neither sure about what you are trying to say there nor I honestly care. See, I think that I have fully covered my being-nice promise, also that my position is quite clear. I don't want to continue with this conversion, please respect that.

A new example of the referred behaviour (calling non-static from static); this time with the peculiarity that it works on my Visual Studio 2012, but not on my 2015 version (?! Might it have to do with the configuration of the compiler? Note that I am using the default one in both cases).

``` C#
public static void CallingStaticMethod()
{
NonStaticMethodNormal("anything"); //It doesn't compile.

dynamic value = "anything";
NonStaticMethodDynamic(value); //It compiles in VS 2012 (wrong IMO), but not in VS 2015 (right IMO).
NonStaticMethodDynamic("anything"); //It doesn't compile.

}

public void NonStaticMethodNormal(string arg) { }
public void NonStaticMethodDynamic(dynamic arg) { }

```

As said, I am working on a somehow big code where I am using dynamic variables a lot (BTW, quite happy with them so far, other than for these compiling-anything issues) and that's why I am finding so many descriptive situations. In any case, I guess that my point is already completely clear and am not planning to post more samples.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ilexp picture ilexp  Â·  167Comments

MadsTorgersen picture MadsTorgersen  Â·  542Comments

mattwar picture mattwar  Â·  190Comments

ghost picture ghost  Â·  229Comments

stephentoub picture stephentoub  Â·  167Comments