I was reading C# in depth and I couldn't understand the para of the chapter
Another method—this time one that already existed in .NET 1.1—that’s
worth exploring is Type.GetType(string), and its related
Assembly.GetType(string) method, both of which provide a dynamic
equivalent to typeof. You might expect to be able to feed each line of
the output of listing 3.11 to the GetType method called on an
appropriate assembly, but unfortunately life isn’t quite that
straightforward. It’s fine for closed constructed types—the type
arguments just go in square brackets. For generic type definitions,
though, you need to remove the square brackets entirely— otherwise
GetType thinks you mean an array type. Listing 3.12 shows all of these
methods in action.
and in the example code author did what he asked not to do I believe :
string listTypeName = "System.Collections.Generic.List`1";
Type defByName = Type.GetType(listTypeName);
Type closedByName = Type.GetType(listTypeName + "[System.String]"); // did here ? , since he passed the listTypeName + [Type args] , so compiler should think it's array?
Type closedByMethod = defByName.MakeGenericType(typeof(string));
or might I got the things wrong , can anyone please elaborate with examples what he meant by line "For generic type definitions, though, you need to remove the square brackets entirely— otherwise GetType thinks you mean an array type"
System.Collections.Generic.List`1[System.String] is the name of the closed generic type.
And the name of the open generic type is not System.Collections.Generic.List`1[] but System.Collections.Generic.List`1.
That's basically all that this paragraph says.
.Net type names passed by string use [<type1>(,<typeN>)] to indicate a generic type/function parameter list. [] on it's own indicates an array type.
Also, any generic type name will have the construct:
`n
After its string name to indicate the number of generic parameters that the type has. So:
MyNamespace.MyType`1
References the open generic type MyNamespace.MyType<> (i.e. with no generic arguments supplied).
Whereas
MyNamespace.MyType`1[System.String]
References the closed generic type MyNamespace.MyType<string>.
Note that there are further rules to do with Type.GetType - that being that you can only omit the assembly name (including public key token if applicable) when either:
The type requested can be found in the calling assembly
The type request is in mscorlib.
So, many core types can be specified by string with just their namespace-qualified name, including the generics - and the same goes for when a type name is specified as a type argument (as with System.String above).
Related
I am trying to get the name of a method on a generic interface. I would expect this to work as the type part would be a valid typeof:
//This does not compile
nameof(IGenericInterface<>.Method)
//This would compile
typeof(IGenericInterface<>)
I think this should be valid c#-6.0 or am I missing something or is there a better way to do this. I don't want to use a string for the Method name as if the method is renamed code would break without any build-time errors.
This is expected. According to the documentation, your expression is disallowed, because it refers to an unbound generic type:
Because the argument needs to be an expression syntactically, there are many things disallowed that are not useful to list. The following are worth mentioning that produce errors: predefined types (for example, int or void), nullable types (Point?), array types (Customer[,]), pointer types (Buffer*), qualified alias (A::B), and unbound generic types (Dictionary<,>), preprocessing symbols (DEBUG), and labels (loop:).
You can work around this limitation by supplying a generic parameter:
nameof(IGenericInterface<object>.Method)
Note: I think Microsoft should tweak nameof feature to allow references to methods of unbound generic types.
Just use a sample type in order to compile.
string name = nameof(IGenericInterface<int>.Method) // will be Method
The solutions presented with "sample types" will work, but sooner or later you will need to get the nameof a generic type which has type constraints, so nameof(MyGenericType<object>) won't work, because object does not abide by the constraints.
If you find yourself in this situation, it might seem that you have to declare a dummy little class real quick which abides by the constraints so that you can get its nameof, but having to do something as hacky as that is a clear indication that you are down the wrong rabbit hole.
Here is a better solution:
typeof(MyGenericType<>).Name
Interestingly enough, C# allows us to use <> in typeof but not in nameof. Go figure.
I am trying to get the name of a method on a generic interface. I would expect this to work as the type part would be a valid typeof:
//This does not compile
nameof(IGenericInterface<>.Method)
//This would compile
typeof(IGenericInterface<>)
I think this should be valid c#-6.0 or am I missing something or is there a better way to do this. I don't want to use a string for the Method name as if the method is renamed code would break without any build-time errors.
This is expected. According to the documentation, your expression is disallowed, because it refers to an unbound generic type:
Because the argument needs to be an expression syntactically, there are many things disallowed that are not useful to list. The following are worth mentioning that produce errors: predefined types (for example, int or void), nullable types (Point?), array types (Customer[,]), pointer types (Buffer*), qualified alias (A::B), and unbound generic types (Dictionary<,>), preprocessing symbols (DEBUG), and labels (loop:).
You can work around this limitation by supplying a generic parameter:
nameof(IGenericInterface<object>.Method)
Note: I think Microsoft should tweak nameof feature to allow references to methods of unbound generic types.
Just use a sample type in order to compile.
string name = nameof(IGenericInterface<int>.Method) // will be Method
The solutions presented with "sample types" will work, but sooner or later you will need to get the nameof a generic type which has type constraints, so nameof(MyGenericType<object>) won't work, because object does not abide by the constraints.
If you find yourself in this situation, it might seem that you have to declare a dummy little class real quick which abides by the constraints so that you can get its nameof, but having to do something as hacky as that is a clear indication that you are down the wrong rabbit hole.
Here is a better solution:
typeof(MyGenericType<>).Name
Interestingly enough, C# allows us to use <> in typeof but not in nameof. Go figure.
foreach (Pair<Pair<int, int>, Cell> cell in sheet.Cells)
{
dgvCells[cell.Left.Right, cell.Left.Left].Value = cell.Right.Value;
}
I am working on creating a excel file from within .NET, using this Excel Library
I am getting the warning mentioned in the title. Any ideas?
Just for future reference, and understanding, the error message:
The non-generic type '' cannot be used with type arguments
is replaced with some class, indicates that within your code you are attempting to make use of a non-generic class in a generic way. More specifically you are using some syntax which is incompatible with that type, in this case the <> generic braces on the type "Pair".
To typically solve the problem
Identify the types use within the file, specifically its use in a generic way. (This should find them: Ctrl + F > "SomeClass<")
Ensure that the type is as expected (F12 on the type should take you to its declaration)
If the type is different to the expected type you should make use of a using alias to point to the correct type namespace i.e.
using Pair = Fully.Qualified.Namespace.Of.Pair;
If the type is as expected ensure that it is generic, if not you can either modify it to be generic, if you have permission/access to do so, or you could select/create a different type which is more suitable for your purpose.
Alternativly you could modify your use of the type to be non-generic
It means that Pair in the code above is referring to System.Web.UI.Pair instead of some other "pair" class such as System.Collections.Generic.KeyValuePair (which is generic).
Depending on which Pair the above code was meant to instantiate, use something like
using Pair = MyNamespace.Pair;
to resolve the issue (this example assumes you really want to use MyNamespace.Pair).
Update:
It seems that in your case the exact solution is
using Pair = QiHe.CodeLib.Pair;
Because MSDN provides the Pair definition as:
[SerializableAttribute]
public sealed class Pair
There is not a definition that includes Pair<T1, T2>. If there is another Pair class, you need to include that namespace in your 'using' clause.
With respect to C# 4.0, which of these two is the correct term: Named parameters or Named arguments? I find many occurences of both terms hence am quite confused how to mention them (say in formal documentation)?
parameters have always been named; in the context of supplying values for a method, they are arguments - however, then name that you are specifying is the parameter name. So I can see how it would become mixed up ;p But in the context, we are supplying to name for the compiler to use to resolve the argument, so "named arguments" ftw.
More specifically:
7.5.1 Argument lists
An argument with an argument-name is referred to as a named argument, whereas an argument without an argument-name is a positional argument. It is an error for a positional argument to appear after a named argument in an argument-list.
MS itself refers to them as "named arguments". They made the language; I'd stick with what they use.
(Unless anyone finds stuff on MSDN referring to "named parameters" in the context of C#.
EDIT: Someone did. Use whatever the hell terminology you want. :)
I've seen them used interchangeably, however I like to use parameters in regards the definition, and arguments in regards the values passed. For example, the following class has a "type parameter":
class A<T> { }
But the following declaration has a "type argument":
var a = new A<string>();
Quoting from the C# 4 Specification:
Since a type parameter can be instantiated with many different actual type arguments, type parameters have slightly different operations and restrictions than other types.
Another quote:
A fixed-parameter with a default-argument is known as an optional parameter, whereas a fixed-parameter without a default-argument is a required parameter.
The only time (AFAIKnew) the C# spec refers to "named arguments" is in regards to Attributes. But when to referring to the new feature, they use "named paramters". So, I would follow that pattern.
Update
Marc has a good point that parameters have always been named, but that doesn't mean that arguments can be named now too. The name still belongs to the parameter and the argument is supplied to it. With the new "named parameters" feature, there are potentially two parts to supplying arguments: the argument itself, and the name of the parameter it is being supplied to.
// The part before the : is the named parameter,
// and the part after the : is the argument
SomeMethod(someParam: someArg);
I know this is splitting hairs, but I still think it's a valid point. As far as I'm concerned, you will be understood whether you use "named parameter" or "named argument". (Plus, section 7.5.1 is still glaring at me.)
In my personal opinion I think that 7.5.1 has it backwards, which is also confirmed by 7.5.1.1 which states:
If no unique parameter list is found, a parameter list with inaccessible names and no optional parameters is constructed, so that invocations cannot use named parameters or omit optional arguments.
In the call you name the parameter that should accept the argument you pass to it.
public static void SayHello(string name = "John Doe", int age = 30)
{
Console.WriteLine("Hello {0}, I see you're {1} years old.", name, age);
}
static void Main(string[] args)
{
SayHello(age:42);
}
Inside Main I haven't passed any argument to the "name" parameter and I don't need to since it has a default value which makes the argument optional (the parameter is not optional since it obviously exist in the SayHello function). I have however specified that the argument 42 should be passed to the "age" parameter (in other words I have named the parameter in the call). If I could name the arguments I should be able to give them arbitrary names:
SayHello(language:"vFred", version:7);
The only reason I would see for allowing "named arguments" would be if I use an API which doesn't use descriptive names for the parameters of a method. Then at least I could at the caller site name the arguments so it makes sense. But alas C# does not allow you to give your arguments any names, it does however allow you to specify the name of the parameter that should accept the argument.
This reasoning is of course only valid if you don't think that arguments and parameters are interchangeable but rather that parameters are the list on the called site while arguments are on the caller site, which is at least how C++ defines them.
Recently I noticed that generic constructed types can be open and closed. But I do not understand what they actually mean. Can you give a simple example?
In practice the terminology doesn't really matter much - I can't remember the last time I had to worry about it except when trying to write about it.
An unbound type has no type arguments specified
A constructed type has at least one type argument specified
A type parameter is an open type
An array type where the element type is open is an open type
An open constructed type has at least one type argument which is an open type
A closed type is any type which isn't open
(There are further rules for nested types. Consult the C# 3.0 spec section 4.4 for gory details.)
As an example of an open constructed type, consider:
public class NameDictionary<T> : Dictionary<string, T>
The base class of typeof(NameDictionary<>) is:
Constructed because it specifies type arguments
Open because the second type argument (T) is an open type
The MSDN docs for Type.IsGenericType have quite a useful little table.
Just to reiterate, this is almost entirely unimportant in day to day use.
I'm generally in favour of knowing the correct terminology - particularly for things like "pass by reference" etc - but in this case it really, really doesn't come up very often. I would like to actively discourage you from worrying about it :)
From MSDN:
A generic type or method is closed if instantiable types have been substituted for all its type parameters, including all the type parameters of all enclosing types. You can only create an instance of a generic type if it is closed.
So this works as List<int> is closed:
var list = Activator.CreateInstance(typeof(List<int>));
But this throws an exception at run-time because List<> is open:
var list = Activator.CreateInstance(typeof(List<>));
↑
I have mostly used open generics (basically uninstantiated generics) in dependency injection mappings. For example, something like
Bind<IRepository<>>()
.To<BasicRepository<>>()
Then, when my object constructor contains:
public SomethingController(IRepository<Something>) { ... }
My dependency injection mechanism will instantiate a BasicRepository< Something > automagically. (This works with Ninject and StructureMap, and probably the Castle Windsor library; I'm not sure about other frameworks).