Implicit type discovery for generics - c#

I was wondering if C# supported implicit type discovery for class generics.
For example, such functionaly exists on method generics.
I can have the following method:
public void Foo<T>(T obj);
And call it like this:
int n = 0;
instance.Foo(n);
As you can see, I'm not specifying the <int> generic constraint. It's being implicitly discovered, because I passed an int value.
I want to accomplish something similiar on a class definition level:
internal interface IPersistenceStrategy<E, T> : IDisposable
where E : UniqueEntity<T>
I want it to be defined as IPersistenceStrategy<MyEntity>, where MyEntity is an UniqueEntity<int>.
As you can see, the T type param, is being implicitly discovered from MyEntity.
However, this does not work. I have to supply the T param explicitly:
IPersistenceStrategy<MyEntity, int> myStrategy;
Why is this functionality not working? Is C# compiler not smart enough to discover my type param automatically?
Is there some way to accomplish what I am looking for?

There is no type inference in generic type declarations on initialization. You can only omit the generic argument when calling a generic method but it is not the case with initializing a generic type for example:
var list = new List { 2, 3, 4 };
Here you may expect compiler to see that you wanna create a list of int so there is no need to specify type argument.But it is not the case.
In your specific example let's assume compiler has inferred this :
IPersistenceStrategy<MyEntity> myStrategy;
as IPersistenceStrategy<MyEntity,int> then what should happen if there is another declaration in the same assembly such as:
interface IPersistenceStrategy<T> { }
Ofcourse this would cause an ambiguity. So that might be the one of the reasons why it is not allowed.

C# has type inference for methods, but not for constructors. This feature was proposed to be in C# 6 version, but seems was removed from release according to Mads Torgersen (http://blogs.msdn.com/b/csharpfaq/archive/2014/11/20/new-features-in-c-6.aspx).
Also have a look to Languages features in C# 6 and VB 14, i.e. there is no mention about it

Related

C# -- Knowing a base type of a Generic Type

How can I find out the base type of a generic type?
For example
Func<A, B>
I'd like to be able to say this is a Func<> .. but apparently, Func<,> is different from Func<> -- Is there a way to somehow catch them both, or Func<,,,> etc?
You're looking for GetGenericTypeDefinition:
var t = typeof(Func<int, string>);
var tGeneric = t.GetGenericTypeDefinition();
Assert.AreEqual(typeof(Func<,>), tGeneric);
If you then want to know if a type is one of the many Func<> variants, then your best best is simply to do something like this. Checking type names, as suggested elsewhere is absolutely NOT the way to check type identity:
static Type[] funcGenerics = new[]{
typeof(Func<>), typeof(Func<,>), typeof(Func<,,>), typeof(Func<,,,>),
/* and so on... */
}
//there are other ways to do the above - but this is the most explicit.
static bool IsFuncType(Type t)
{
if(t.IsGenericTypeDefinition)
return funcGenerics.Any(tt => tt == t);
else if(t.IsGenericType)
return IsFuncType(t.GetGenericTypeDefinition());
return false;
}
Your terminology is incorrect - which I suspect why you got a downvote on your question. A base type is one that a type inherits from (not an interface, which is different, although conceptually very similar).
A generic type definition is best thought of as being like a template (the strong qualification there because the term 'template' is used in C++ and, while visually similar they are very different in implementation).
More accurately, Func<,> is a generic type definition whereas Func<int, string> is a closed generic (the 'generic type').
You can also have an open generic, which is where the type arguments are generic parameters - e.g, given:
class MyType<T> : List<T> { }
Then List<T> is an open generic with the generic type definition List<>, because T is a generic parameter which will not be closed till MyType<T> is referenced with a concrete type argument, such as int or string.
Finally, just because a bunch of generic types share the same common name, e.g. Func<>, Func<,>, and Func<,,> it does not mean they are in any way related. At the type level, there is no explicit connection, which is why you have to check for all these type identities, and why there is no common 'base' as you put it. If they all had a common interface or base class, however, then you could - by checking for compatibility with that interface or base type.
Given a generic type definition, you can construct generic types using MakeGenericType, as has been mentioned by Jeffrey Zhang.
No, you can't, There is not a base type of a Gerneric Type. If you want to get a specific generic type by type parameters, You can use MakeGenericType. For example:
//get Func<int, string> type
typeof(Func<>).MakeGenericType(typeof(int), typeof(string));
If you want to get a Generic Type from specified generic type, You can use GetGenericTypeDefinition. For example:
//get Func<,> type
typeof(Func<int, string>).GetGenericTypeDefinition();
It is Because Func< A, B > does not inherit from Func<> It is a generic based on Func<,>.
However, you will notice that
typeof(Func<int, int>).FullName // equals "System.Func`2...
typeof(Func<int, int, int>).FullName // equals "System.Func`3...
It is a bit ugly but you could use something like
YourType.FullName.StartsWith("System.Func")
Hope it helps
Edit:
Why not use YourType.GetGenericTypeDefinition()?
Because typeof(Func<int, int>).GetGenericTypeDefinition() returns Func<,>
and typeof(Func<int, int, int>).GetGenericTypeDefinition() return Func<,,>.
Func<,> and Func<,,> are not the same Type.

Are Generic Generic type parameters in C# allowed in some form

I would like to create the following class snippet
class Lookup<TKey,TValue,TCollection>
where TCollection : ICollection<>
{
public TCollection<TKey> _KeyCollection;
public TCollection<TValue> _ValueCollection;
}
Is this pattern in general possible in C#? In the current form the compiler does not like it. You can't seem to constrain a type parameter to be a generic. However it looks like it a reasonable thing to want to do. Is there any trick to achieve it?
Note: This question is specifically about generics and type constraints. It is not looking for a work around for what you think I might be trying to do in my wider application.
You can't constrain a generic type parameter to be an open generic type, which seems to be how you're attempting to use it in the rest of the class.
You asked for a spec reference, and there's not one place that seems to spell it out in a nice, concise manner.
The best I can find is in section 4.5 (from C# 5.0 spec):
As a type, type parameters are purely a compile-time construct. At run-time, each type parameter is bound to a run-time type that was specified by supplying a type argument to the generic type declaration. Thus, the type of a variable declared with a type parameter will, at run-time, be a closed constructed type (§4.4.2). The run-time execution of all statements and expressions involving type parameters uses the actual type that was supplied as the type argument for that parameter.
But in your attempt, TCollection won't match up with this text because it's asking for an non-closed type.
You can't have an open generic type as a constraint. You can, however, have a closed generic type:
class Lookup<TKey, TValue, TKeyCollection, TValueCollection>
where TKeyCollection : ICollection<TKey>
where TValueCollection : ICollection<TValue>
{
public TKeyCollection _KeyCollection;
public TValueCollection _ValueCollection;
}
It may not be pretty and there are a lot of type parameters, but it is possible.

Generic class can product identical signature overloads? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Generic methods and method overloading
Ok, I hit this one by accident... Giving this situation:
class Program {
static void Main( string[ ] args ) {
var obj = new gen<int>( );
Console.Write( obj[ 1 ] );
Console.ReadKey( );
}
}
class gen<T> {
public int this[ T i ] { get { return 2; } }
public int this[ int i ] { get { return 1; } }
}
It will always print 1. I would have expected for the compiler to complain, or the runtime to crash and burn and melt the CPU, but no, it is happy to print '1'
Of course I can make a choice to return either if I use any other type for the generic parameter. For giggles, I try using UInt as the generic type parmater, and I can differentiate between the calls, so the questions are:
Why C# does not freak out? Shouldn't Anders Hejlsberg feel a disturbance in the force?
How can I restrict a generic parameter from certain types? As in this T can be anything but ints (but long are OK)
I believe this is specified in section 7.5.3.2 of the C# 4 spec (Better Function Member).
Otherwise, if MP has more specific parameter types than MQ, then MP is better than MQ [...]
A type parameter is less specific than a nontype parameter
[...]
So here, the member with the T parameter is less specific than the member with the int parameter.
Try to design your way out of this one simply by not overloading like this. It's hard for indexers of course, but you could always provide methods instead (or possibly as well, as a fall-back).
EDIT: Note that if you have overloaded methods where both are type parameters, the compiler will complain:
public class Foo<T1, T2>
{
public void Bar(T1 t1) {}
public void Bar(T2 t2) {}
}
...
Foo<int, int> foo = new Foo<int, int>();
foo.Bar(10); // Error
Here neither method is more specific.
How can I restrict a generic parameter from certain types? As in this T can be anything but ints (but long are OK)
This is really an entirely separate question, but basically you can't. You can constrain type parameters in various ways, but not by explicitly including and excluding types. See the MSDN page on constraints for more information.
As Eric Lippert says:
The C# specification says that when you have a choice between calling ReallyDoIt(string) and ReallyDoIt(string) – that is,
when the choice is between two methods that have identical signatures,
but one gets that signature via generic substitution – then we pick
the “natural” signature over the “substituted” signature.
Also this process described in C# spec 7.5.3.2 (Better function member):
In case the parameter type sequences {P1, P2, …, PN} and {Q1, Q2, …, QN} are equivalent (i.e. each Pi has an identity conversion to the corresponding Qi), the following tie-breaking rules are applied, in order, to determine the better function member.
If MP is a non-generic method and MQ is a generic method, then MP is better than MQ (as John pointed, this is true when you have generic method, not generic type)
...
Otherwise, if MP has more specific parameter types than MQ, then MP is better than MQ. Let {R1, R2, …, RN} and {S1, S2, …, SN} represent the uninstantiated and unexpanded parameter types of MP and MQ. MP’s parameter types are more specific than MQ’s if, for each parameter, RX is not less specific than SX, and, for at least one parameter, RX is more specific than SX:
A type parameter is less specific than a non-type parameter (this is your case - thus methods are not generic, and inferred parameter type equals to non-generic parameter type)
The C# compiler always chooses the more-specific versus the more-generic method if the call could fit in both =). That's why it doesn't freak out, he just follows his rules.
C# compiler doesn't freak out because both method are valid, and both can be called.
Here's an example that return "2":
Gen<Form> gen = new Gen<Form>();
textBox1.Text = gen[this].ToString();
Where "this" is a form. Of course, using an index accessor as an object instead of a number... Well, whatever, it works.
But like everybody else said, the compiler will prefer the explicit over the implicit.

C# Nested generics treated differently when using constraints

When using nested generics, the compiler fails when used directly yet compiles correctly when using constraints.
Example:
public static void Test1<V, E>(this Dictionary<V, E> dict)
where V : IVertex
where E : IEdge<V>
{}
public static void Test2(this Dictionary<IVertex, IEdge<IVertex>> dict){}
The two extension methods above have ostensibly the same signature, but if I was to now try to run code such as:
var dict = new Dictionary<VertexInstance, EdgeInstance>();
dict.Test1();
dict.Test2();
the compiler would err on 'Test2' stating that it could not convert to the generic form with the inline nested generic. Personally I find the syntax for Test2 to be more intuitive.
I posted this originally as an answer in a question which asked about differences between using generic constraints and using interfaces directly, but I am curious as to why this happens?
Expanding my comment:
These extension methods of course do not have the same signature. Dictionary<IVertex, IEdge<IVertex>> is not the same as Dictionary<VertexInstance, EdgeInstance>. #Payo is correct; this is a question of variance. Classes cannot be co- or contravariant. Interfaces can, but only if they're marked for it, and IDictionary cannot be marked for it because it wouldn't be safe, so changing to IDictionary wouldn't help here.
Consider if this were allowed. Your Test2 implementation could look like this:
public static void Test2(this Dictionary<IVertex, IEdge<IVertex>> dict)
{
dict.Add(new EvilVertex(), new EvilEdge());
}
EvilVertex and EvilEdge could implement the correct interfaces, but not inherit from VertexInstance and EdgeInstance. The call would then fail at runtime. The call to Test2 is therefore not provably safe, so the compiler does not allow it.
Thank you for the answer; however, the constraints version could have the same code inside and would have the same issue, wouldn't it?
No! The constraints version could not have the same code inside, because you can't convert from EvilVertex to V, nor from EvilEdge to E. You could force a cast from the type to the type parameter, by casting first to object, but that would of course fail at run time.
Also, why is variance controlled at that level?
Because one purpose of generics is to prove the code's type safety at compile time.
Your dict.Add should have the compilation error not the extension method in my view.
As mentioned, the call to dict Add is a compiler error for the generic version. It can't be a compiler error for the interface version, because in the context of Test2, all you know is that you're converting EvilVertex to IVertex, which is perfectly legal.

Why it isn't possible to declare a method parameter as var type

I wonder why it is not possible a method parameter as var type like
private void myMethod(var myValue) {
// do something
}
You can only use var for variables inside the method body. Also the variable must be assigned at declaration and it must be possible to deduce the type unambiguously from the expression on the right-hand side.
In all other places you must specify a type, even if a type could in theory be deduced.
The reason is due to the way that the compiler is designed. A simplified description is that it first parses everything except method bodies and then makes a full analysis of the static types of every class, member, etc. It then uses this information when parsing the method bodies, and in particular for deducing the type of local variables declared as var. If var were allowed anywhere then it would require a large change to the way the compiler works.
You can read Eric Lippert's article on this subject for more details:
Why no var on fields?
Because the compiler determines the actual type by looking at the right hand side of the assignment. For example, here it is determined to be a string:
var s = "hello";
Here it is determined to be Foo:
var foo = new Foo();
In method arguments, there is no "right hand side of the assignment", so you can't use var.
See the posting by Eric Lippert about why var is not allowed on fields, which also contains the explanation why it doesn't work in method signatures:
Let me give you a quick oversimplification of how the C# compiler works. First we run through every source file and do a "top level only" parse. That is, we identify every namespace, class, struct, enum, interface, and delegate type declaration at all levels of nesting. We parse all field declarations, method declarations, and so on. In fact, we parse everything except method bodies; those, we skip and come back to them later.
[...]
if we have "var" fields then the type of the field cannot be determined until the expression is analyzed, and that happens after we already need to know the type of the field.
Please see Juliet's answer for a better answer to this question.
Because it was too hard to add full type inference to C#.
Other languages such as Haskell and ML can automatically infer the most general type without you having to declare it.
The other answers state that it's "impossible" for the compiler to infer the type of var but actually it is possible in principle. For example:
abstract void anotherMethod(double z, double w);
void myMethod<T>(T arg)
{
anotherMethod(arg, 2.0); // Now a compiler could in principle infer that arg must be of type double (but the actual C# compiler can't)
}
Have "var" method parameters is in principle the same thing as generic methods:
void myMethod<T>(T arg)
{
....
}
It is unfortunate that you can't just use the same syntax for both but this is probably due to the fact that that C#'s type inference was added only later.
In general, subtle changes in the language syntax and semantics can turn a "deterministic" type inference algorithm into an undecidable one.
ML, Haskell, Scala, F#, SML, and other languages can easily figure out the type from equivalent expressions in their own language, mainly because they were designed with type-inference in mind from the very start. C# wasn't, its type-inference was tacked on as a post-hoc solution to the problem of accessing anonymous types.
I speculate that true Hindley-Milner type-inference was never implemented for C# because its complicated to deduce types in a language so dependent on classes and inheritance. Let's say I have the following classes:
class Base { public void Print() { ... } }
class Derived1 : Base { }
class Derived2 : Base { }
And now I have this method:
var create() { return new Derived1(); }
What's the return type here? Is it Derived1, or should it be Base? For that matter, should it be object?
Ok, now lets say I have this method:
void doStuff(var someBase) { someBase.Print(); }
void Main()
{
doStuff(new Derived1());
doStuff(new Derived2()); // <-- type error or not?
}
The first call, doStuff(new Derived1()), presumably forces doStuff to the type doStuff(Derived1 someBase). Let's assume for now that we infer a concrete type instead of a generic type T.
What about the second call, doStuff(new Derived1())? Is it a type error, or do we generalize to doStuff<T>(T somebase) where T : Base instead? What if we made the same call in a separate, unreferenced assembly -- the type inference algorithm would have no idea whether to use the narrow type or the more genenarlized type. So we'd end up with two different type signatures based on whether method calls originate from inside the assembly or a foreign assembly.
You can't generalize wider types based on usage of the function. You basically need to settle on a single concrete type as soon as you know which concrete type is being pass in. So in the example code above, unless you explicitly cast up to the Base type, doStuff is constrained to accept types of Derived1 and the second call is a type error.
Now the trick here is settling on a type. What happens here:
class Whatever
{
void Foo() { DoStuff(new Derived1()); }
void Bar() { DoStuff(new Derived2()); }
void DoStuff(var x) { ... }
}
What's the type of DoStuff? For that matter, we know based on the above that one of the Foo or Bar methods contain a type error, but can you tell from looking which has the error?
Its not possible to resolve the type without changing the semantics of C#. In C#, order of method declaration has no impact on compilation (or at least it shouldn't ;) ). You might say instead that the method declared first (in this case, the Foo method) determines the type, so Bar has an error.
This works, but it also changes the semantics of C#: changes in method order will change the compiled type of the method.
But let's say we went further:
// Whatever.cs
class Whatever
{
public void DoStuff(var x);
}
// Foo.cs
class Foo
{
public Foo() { new Whatever().DoStuff(new Derived1()); }
}
// Bar.cs
class Bar
{
public Bar() { new Whatever().DoStuff(new Derived2()); }
}
Now the methods is being invoked from different files. What's the type? Its not possible to decide without imposing some rules on compilation order: if Foo.cs gets compiled before Bar.cs, the type is determined by Foo.cs.
While we can impose those sorts of rules on C# to make type inference work, it would drastically change the semantics of the language.
By contrast, ML, Haskell, F#, and SML support type inference so well because they have these sorts of restrictions: you can't call methods before they're declared, the first method call to inferred functions determines the type, compilation order has an impact on type inference, etc.
The "var" keyword is used in C# and VB.NET for type inference - you basically tell the C# compiler: "you figure out what the type is".
"var" is still strongly typed - you're just too lazy yourself to write out the type and let the compiler figure it out - based on the data type of the right-hand side of the assignment.
Here, in a method parameter, the compiler has no way of figuring out what you really meant. How? What type did you really mean? There's no way for the compiler to infer the type from the method definition - therefore it's not a valid statement.
Because c# is type safe and strong type language. At any place of your program compiler always knows the type of argument you are using. var keyword was just introduced to have variables of anonymus types.
Check dynamic in C# 4
Type inference is type inference, either in local expressions or global / interprocedural. So it isn't about "not having a right hand side", because in compiler theory, a procedure call is a form of "right hand side".
C# could do this if the compiler did global type inference, but it does not.
You can use "object" if you want a parameter that accepts anything, but then you need to deal with the runtime conversion and potential exceptions yourself.
"var" in C# isn't a runtime type binding, it is a compile time feature that ends up with a very specific type, but C# type inference is limited in scope.

Categories

Resources