Dynamic type in Generics - c#

I'm currently looking into C# Generics, and I have a few questions.
1) In the following code, will the comparison of the type of T in "Test" slow down the program? In other languages this is handled on compile time, but I don't know about C#.
2) Since sizeof apparently won't work, I have to use System.Runtime.InteropServices.Marshal.SizeOf. Is this correct?
3) I haven't seen code like this in C# yet, is there anything wrong about it, or is it perfectly fine what I'm doing here? In the end the method in this example would take a handful of types, and throw and exception if it can't handle it. Some types would be handled independently, others like short/int/long would be handled together, depending on their size.
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Test<int>();
Test<long>();
Test<string>();
Console.ReadLine();
}
static void Test<T>()
{
Type type = typeof(T);
if (type == typeof(int) || type == typeof(long))
{
Console.WriteLine("int");
Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(type).ToString());
}
else if (type == typeof(string))
{
Console.WriteLine("string");
}
}
}
}

1) It will be done at runtime, not compile-time. This isn't C++ templates. That said, it's a pretty fast operation.
3) If there are a fixed number of types that you need to support your better off using method overloading than generics.
Have Test(int input),Test(string input), and so on for each type you need to support. You can have a generic method in addition to those if there is a "general case" to support for everything else.

Yes, the type comparison slows it down, not that such an operation will significantly affect anything done only once. If you're doing this in a tight loop somewhere... consider not doing it. This is because it creates a Type object and compares those Type objects - it's not a compile-time check.
Yes, Marshal.SizeOf is correct1. I don't know what C#'s sizeof does, though, because I'm a VB.NET person.
As for not seeing this type of code much in C#, that's probably because it's not a case that people often come across. And also, instead of doing what you're doing, you should be offering method overloads for each type; cleaner, and the error is at compile-time, not runtime.
1 You're just printing it out, it's correct to print it out. I don't know what the goal of all this is, though.

Related

Generic interface type inference weirdness in c#

C# cannot infer a type argument in this pretty obvious case:
public void Test<T>(IEnumerable<KeyValuePair<string, T>> kvp)
{
Console.WriteLine(kvp.GetType().Name + ": KeyValues");
}
Test(new Newtonsoft.Json.Linq.JObject());
The JObject type clearly implements IEnumerable<KeyValuePair<string, JToken>>, but I get the following error:
CS0411: The type arguments for method cannot be inferred from the usage.
Why does this happen?
UPD: To the editor who marked this question as duplicate: please note how my method's signature accepts not IEnumerable<T>, but IEnumerable<KeyValuePair<string, T>>. The JObject type implements IEnumerable twice, but only one of the implementations matches this constraint - so there should be no ambiguity.
UPD: Here's a complete self-contained repro without JObject:
https://gist.github.com/impworks/2eee2cd0364815ab8245b81963934642
Here's a simpler repro:
interface I<T> {}
class X<T> {}
class Y {}
class Z {}
class C : I<X<Y>>, I<Z> {}
public class P
{
static void M<T>(I<X<T>> i) { }
public static void Main()
{
M(new C());
}
}
Type inference fails. You ask why, and why questions are always difficult to answer, so let me rephrase the question:
What line of the specification disallows this inference?
I have my copy of the C# 3 specification at hand; the line there is as follows
V is the type we are inferring to, so I<X<T>> in this case
U is the type we are inferring from, so C in this case
This will be slightly different in C# 4 because I added covariance, but we can ignore that for the purposes of this discussion.
... if V is a constructed type C<V1, … Vk> and there is a unique set of types U1, … Uk such that an implicit conversion exists from U to C<U1, … Uk> then an exact inference is made from each Ui to the corresponding Vi. Otherwise no inferences are made.
Notice the word unique in there. There is NOT a unique set of types such that C is convertible to I<Something> because both X<Y> and Z are valid.
Here's another non-why question:
What factors were considered when the design team made this decision?
You are right that in theory we could detect in your case that X<Y> is intended and Z is not. If you would care to propose a type inference algorithm that can handle non-unique situations like this that never makes a mistake -- remember, Z could be a subtype or a supertype of X<Y> or X<Something Else> and I could be covariant -- then I am sure that the C# team would be happy to consider your proposal.
We had that argument in 2005 when designing the C# 3 type inference algorithm and decided that scenarios where one class implements two of the same interface were rare, and that dealing with those rare situations created considerable complications in the language. Those complications would be expensive to design, specify, implement and test, and we had other things to spend money and effort on that would have bigger impact.
Also, we did not know when we made C# 3 whether or not we would be adding covariance in C# 4. We never want to introduce a new language feature that makes a possible future language feature impossible or difficult. It is better to put restrictions in the language now and consider removing them later than to do a lot of work for a rare scenario that makes a common scenario difficult in the next version.
The fact that I helped design this algorithm and implemented it multiple times, and completely did not remember this rule at first should tell you how often this has come up in the last 13 years. Hardly at all. It is very rare for someone to be in your particular boat, and there is an easy workaround: specify the type.
A question which you did not ask but comes to mind:
Could the error message be better?
Yep. I apologize for that. I did a lot of work making overload resolution error messages more descriptive for common LINQ scenarios, and I always wanted to go back and make the other type inference error messages more clear. I wrote the type inference and overload resolution code to maintain internal information explaining why a type had been inferred or an overload had been chosen or rejected, both for my own debugging purposes and to make better error messages, but I never got around to exposing that information to the user. There was always something higher priority.
You might consider entering an issue at the Roslyn GitHub site suggesting that this error message be improved to help users diagnose the situation more easily. Again, the fact that I didn't immediately diagnose the problem and had to go back to the spec is indicative that the message is unclear.
Problem is following.
If you don't specify type then it will try to infer automatically but if it get confuse then it throw specified exception.
In your case JObject has implemented interface IEnumerable<KeyValuePair<string, JToken>>.
Also JObject implemented JContainer and it also implemented IEnumerable< JToken>.
So when it is specified for T it is confuse between IEnumerable<JToken> and IEnumrable<KeyValuePair<string, JToken>>.
I suspect that when people who designed C# were thinking about how compiler would infer the type for a generic type parameter they thought about potential issues with that.
Consider the following scenario:
class MyClass : JObject, IEnumerable<KeyValuePair<string, int>>
{
public IEnumerator<KeyValuePair<string, int>> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
class Foo : MyClass { }
class FooBar : Foo { }
public void Test<T>(IEnumerable<KeyValuePair<string, T>> kvp)
{
Console.WriteLine(kvp.GetType().Name + ": KeyValues");
}
var fooBar = new FooBar();
Test(fooBar);
Which type should the T be inferred to? int, or JToken ?
Also how complex should the algorithm be ?
Presumably that's why compiler only infers the type when there is no chance for ambiguity. It was designed this way and not without a reason.

Are the placeholders of Generics compiled as an actual data type? [duplicate]

I had thought that Generics in C# were implemented such that a new class/method/what-have-you was generated, either at run-time or compile-time, when a new generic type was used, similar to C++ templates (which I've never actually looked into and I very well could be wrong, about which I'd gladly accept correction).
But in my coding I came up with an exact counterexample:
static class Program {
static void Main()
{
Test testVar = new Test();
GenericTest<Test> genericTest = new GenericTest<Test>();
int gen = genericTest.Get(testVar);
RegularTest regTest = new RegularTest();
int reg = regTest.Get(testVar);
if (gen == ((object)testVar).GetHashCode())
{
Console.WriteLine("Got Object's hashcode from GenericTest!");
}
if (reg == testVar.GetHashCode())
{
Console.WriteLine("Got Test's hashcode from RegularTest!");
}
}
class Test
{
public new int GetHashCode()
{
return 0;
}
}
class GenericTest<T>
{
public int Get(T obj)
{
return obj.GetHashCode();
}
}
class RegularTest
{
public int Get(Test obj)
{
return obj.GetHashCode();
}
}
}
Both of those console lines print.
I know that the actual reason this happens is that the virtual call to Object.GetHashCode() doesn't resolve to Test.GetHashCode() because the method in Test is marked as new rather than override. Therefore, I know if I used "override" rather than "new" on Test.GetHashCode() then the return of 0 would polymorphically override the method GetHashCode in object and this wouldn't be true, but according to my (previous) understanding of C# generics it wouldn't have mattered because every instance of T would have been replaced with Test, and thus the method call would have statically (or at generic resolution time) been resolved to the "new" method.
So my question is this: How are generics implemented in C#? I don't know CIL bytecode, but I do know Java bytecode so I understand how Object-oriented CLI languages work at a low level. Feel free to explain at that level.
As an aside, I thought C# generics were implemented that way because everyone always calls the generic system in C# "True Generics," compared to the type-erasure system of Java.
In GenericTest<T>.Get(T), the C# compiler has already picked that object.GetHashCode should be called (virtually). There's no way this will resolve to the "new" GetHashCode method at runtime (which will have its own slot in the method-table, rather than overriding the slot for object.GetHashCode).
From Eric Lippert's What's the difference, part one: Generics are not templates, the issue is explained (the setup used is slightly different, but the lessons translate well to your scenario):
This illustrates that generics in C# are not like templates in C++.
You can think of templates as a fancy-pants search-and-replace
mechanism.[...] That’s not how generic types work; generic types are,
well, generic. We do the overload resolution once and bake in the
result. [...] The IL we’ve generated for the generic type already has
the method its going to call picked out. The jitter does not say
“well, I happen to know that if we asked the C# compiler to execute
right now with this additional information then it would have picked a
different overload. Let me rewrite the generated code to ignore the
code that the C# compiler originally generated...” The jitter knows
nothing about the rules of C#.
And a workaround for your desired semantics:
Now, if you do want overload resolution to be re-executed at runtime based on the runtime types of
the arguments, we can do that for you; that’s what the new “dynamic”
feature does in C# 4.0. Just replace “object” with “dynamic” and when
you make a call involving that object, we’ll run the overload
resolution algorithm at runtime and dynamically spit code that calls
the method that the compiler would have picked, had it known all the
runtime types at compile time.

Using enums in generic methods in C#

I just started learning C# today, and I am trying to make a generic method which can operate on different enums. I got some code that I found in another question on paper, but the compiler keeps complaining. I was wondering if someone could give me a hand. Here is what I have so far:
static void ReadMenuInput<T>(out T menuInput)
{
while (true)
{
if (enum<T>.TryParse(Console.ReadLine(), out menuInput) && menuInput < sizeof(T))
{
break;
}
Console.WriteLine("Please enter a valid input.");
}
}
Thank you for your help!
There are a couple of different issues with that particular code snippet, some of them easier to deal with than others. A few of them are simply showing your lack of experience:
enum and Enum are not interchangable; one is a class name and one is a C# keyword. In some cases (say, string and String) the keyword is just an alias for the type, but enum is not a type name, it is used to define type names. To call class methods you need to use Enum.
You are trying to call the generic TryParse<> method with the wrong syntax; it should be Enum.TryParse<T>.
Enumerations and integers are not the same type, and you cannot just compare them. They are, however, convertible to one another via an explicit typecast. Since sizeof returns an int, you need such a typecast (but see below).
The more complex issues with your code sample:
sizeof(enum) doesn't do quite what you expect, I think; it returns the size in bytes of the enum, which is typically going to be 4. You probably want the IsDefined method, which lets you know if a particular integer value is defined in an enumerated type
As the compiler will tell you, you can only use generic types in this context that are non-nullable. The way to define this is with a where T: struct constraint on your generic type. Note that, despite its name, this doesn't force your type to be a structure; it simply forces it to be a value type.
There is no way for you specify a constraint on the generic type that it must be an enumerated type; if you pass some other value type into the method, it will throw an exception at run-time. It's up to you to handle this case properly.
Here's a working (as in -- it compiles -- I haven't actually tested it) version of the code snippet you want. However, I will point out that every one of the problems in your original code would be worked out just by reading and understanding the error messages; this is one of the most important skills you should get good at as a C# developer.
static void ReadMenuInput<T>(out T menuInput) where T : struct
{
while (true)
{
if (Enum.TryParse<T>(Console.ReadLine(), out menuInput)
&& Enum.IsDefined(typeof(T), menuInput))
{
break;
}
Console.WriteLine("Please enter a valid input.");
}
}

Why does a method invocation expression have type dynamic even when there is only one possible return type?

Inspired by this question.
Short version: Why can't the compiler figure out the compile-time type of M(dynamic arg) if there is only one overload of M or all of the overloads of M have the same return type?
Per the spec, §7.6.5:
An invocation-expression is dynamically bound (§7.2.2) if at least one of the following holds:
The primary-expression has compile-time type dynamic.
At least one argument of the optional argument-list has compile-time type dynamic and the primary-expression does not have a delegate type.
It makes sense that for
class Foo {
public int M(string s) { return 0; }
public string M(int s) { return String.Empty; }
}
the compiler can't figure out the compile-time type of
dynamic d = // dynamic
var x = new Foo().M(d);
because it won't know until runtime which overload of M is invoked.
However, why can't the compiler figure out the compile-time type if M has only one overload or all of the overloads of M return the same type?
I'm looking to understand why the spec doesn't allow the compiler to type these expressions statically at compile time.
UPDATE: This question was the subject of my blog on the 22nd of October, 2012. Thanks for the great question!
Why can't the compiler figure out the compile-type type of M(dynamic_expression) if there is only one overload of M or all of the overloads of M have the same return type?
The compiler can figure out the compile-time type; the compile-time type is dynamic, and the compiler figures that out successfully.
I think the question you intended to ask is:
Why is the compile-time type of M(dynamic_expression) always dynamic, even in the rare and unlikely case that you're making a completely unnecessary dynamic call to a method M that will always be chosen regardless of the argument type?
When you phrase the question like that, it kinda answers itself. :-)
Reason one:
The cases you envision are rare; in order for the compiler to be able to make the kind of inference you describe, enough information must be known so that the compiler can do almost a full static type analysis of the expression. But if you are in that scenario then why are you using dynamic in the first place? You would do far better to simply say:
object d = whatever;
Foo foo = new Foo();
int x = (d is string) ? foo.M((string)d) : foo((int)d);
Obviously if there is only one overload of M then it is even easier: cast the object to the desired type. If it fails at runtime because the cast it bad, well, dynamic would have failed too!
There's simply no need for dynamic in the first place in these sorts of scenarios, so why would we do a lot of expensive and difficult type inference work in the compiler to enable a scenario we don't want you using dynamic for in the first place?
Reason two:
Suppose we did say that overload resolution has very special rules if the method group is statically known to contain one method. Great. Now we've just added a new kind of fragility to the language. Now adding a new overload changes the return type of a call to a completely different type -- a type which not only causes dynamic semantics, but also boxes value types. But wait, it gets worse!
// Foo corporation:
class B
{
}
// Bar corporation:
class D : B
{
public int M(int x) { return x; }
}
// Baz corporation:
dynamic dyn = whatever;
D d = new D();
var q = d.M(dyn);
Let's suppose that we implement your feature requiest and infer that q is int, by your logic. Now Foo corporation adds:
class B
{
public string M(string x) { return x; }
}
And suddenly when Baz corporation recompiles their code, suddenly the type of q quietly turns to dynamic, because we don't know at compile time that dyn is not a string. That is a bizarre and unexpected change in the static analysis! Why should a third party adding a new method to a base class cause the type of a local variable to change in an entirely different method in an entirely different class that is written at a different company, a company that does not even use B directly, but only via D?
This is a new form of the Brittle Base Class problem, and we seek to minimize Brittle Base Class problems in C#.
Or, what if instead Foo corp said:
class B
{
protected string M(string x) { return x; }
}
Now, by your logic,
var q = d.M(dyn);
gives q the type int when the code above is outside of a type that inherits from D, but
var q = this.M(dyn);
gives the type of q as dynamic when inside a type that inherits from D! As a developer I would find that quite surprising.
Reason Three:
There is too much cleverness in C# already. Our aim is not to build a logic engine that can work out all possible type restrictions on all possible values given a particular program. We prefer to have general, understandable, comprehensible rules that can be written down easily and implemented without bugs. The spec is already eight hundred pages long and writing a bug-free compiler is incredibly difficult. Let's not make it more difficult. Not to mention the expense of testing all those crazy cases.
Reason four:
Moreover: the language affords you many opportunities to avail yourself of the static type analyzer. If you are using dynamic, you are specifically asking for that analyzer to defer its action until runtime. It should not be a surprise that using the "stop doing static type analysis at compile time" feature causes static type analysis to not work very well at compile time.
An early design of the dynamic feature had support for something like this. The compiler would still do static overload resolution, and introduced a "phantom overload" that represents dynamic overload resolution only if necessary.
Blog post introducing phantom methods
Details on phantom methods
As you can see in the second post, this approach introduces a lot of complexity (the second article talks about how type inference would need to be modified to make the approach work out). I'm not surprised that the C# team decided to go with the simpler idea of always using dynamic overload resolution when dynamic is involved.
However, why can't the compiler figure out the compile-time type if M has only one overload or all of the overloads of M return the same type?
The compiler could potentially do this, but the language team decided not to have it work this way.
The entire purpose of dynamic is to have all expressions using dynamic execute with "their resolution is deferred until the program is run" (C# spec, 4.2.3). The compiler explicitly does not perform static binding (which would be required to get the behavior you want here) for dynamic expressions.
Having a fallback to static binding if there was only a single binding option would force the compiler to check this case - which was not added in. As for why the language team didn't want to do it, I suspect Eric Lippert's response here applies:
I am asked "why doesn't C# implement feature X?" all the time. The answer is always the same: because no one ever designed, specified, implemented, tested, documented and shipped that feature.
I think the case of being able to statically determine the only possible return type of a dynamic method resolution is so narrow that it would be more confusing and inconsistent if the C# compiler did it, rather than having across the board behavior.
Even with your example, what if Foo is part of a different dll, Foo could be a newer version at runtime from a binding redirect with additional M's that have a different return type, and then the compiler would have guessed wrong because the runtime resolution would return a different type.
What if Foo is an IDynamicMetaObjectProvider d might not match any of the static arguments and thus it would fall back on it's dynamic behavior which could possibly return a different type.

c#: Why isn't this ambiguous enum reference resolved using the method signature?

Consider the following code:
namespace ConsoleApplication
{
using NamespaceOne;
using NamespaceTwo;
class Program
{
static void Main(string[] args)
{
// Compilation error. MyEnum is an ambiguous reference
MethodNamespace.MethodClass.Frobble(MyEnum.foo);
}
}
}
namespace MethodNamespace
{
public static class MethodClass
{
public static void Frobble(NamespaceOne.MyEnum val)
{
System.Console.WriteLine("Frobbled a " + val.ToString());
}
}
}
namespace NamespaceOne
{
public enum MyEnum
{
foo, bar, bat, baz
}
}
namespace NamespaceTwo
{
public enum MyEnum
{
foo, bar, bat, baz
}
}
The compiler complains that MyEnum is an ambiguous reference in the call to Frobble(). Since there is no ambiguity in what method is being called, one might expect the compiler to resolve the type reference based on the method signature. Why doesn't it?
Please note that I'm not saying that the compiler should do this. I'm confident that there is a very good reason that it doesn't. I would simply like to know what that reason is.
Paul is correct. In most situation in C# we reason "from inside to outside".
there is no ambiguity in what method is being called,
That it is unambiguous to you is irrelevant to the compiler. The task of overload resolution is to determine whether the method group Frobble can be resolved to a specific method given known arguments. If we can't determine what the argument types are then we don't even try to do overload resolution.
Method groups that just happen to contain only one method are not special in this regard. We still have to have good arguments before overload resolution can succeed.
There are cases where we reason from "outside to inside", namely, when doing type analysis of lambdas. Doing so makes the overload resolution algorithm exceedingly complicated and gives the compiler a problem to solve that is at least NP-HARD in bad cases. But in most scenarios we want to avoid that complexity and expense; expressions are analyzed by analyzing child subexpressions before their parents, not the other way around.
More generally: C# is not a "when the program is ambiguous use heuristics to make guesses about what the programmer probably meant" language. It is a "inform the developer that their program is unclear and possibly broken" language. The portions of the language that are designed to try to resolve ambiguous situations -- like overload resolution or method type inference or implicitly typed arrays -- are carefully designed so that the algorithms have clear rules that take versioning and other real-world aspects into account. Bailing out as soon as one part of the program is ambiguous is one way we achieve this design goal.
If you prefer a more "forgiving" language that tries to figure out what you meant, VB or JScript might be better languages for you. They are more "do what I meant not what I said" languages.
I believe its because the C# compiler won't typically backtrack.
NamespaceOne and NamespaceTwo are defined in the same code file. That would be equivalent to putting them in different code files and referencing them via using statement.
In that case you can see why the names clash. You have equally named enum in two different namesapces and the compiler can't guess which one it is, even though Frobble has a NamespaceOne.MyEnum parameter. Instead of
MethodNamespace.MethodClass.Frobble(MyEnum.foo)
use
MethodNamespace.MethodClass.Frobble(NamespaceOne.MyEnum.foo)

Categories