Enum type argument not working - c#

This may be a basic question, but I googled it and didn't find an answer. I hope you will help me. Consider I have an enum ContactNumberType:
string[] names = Enum.GetNames(typeof(ContactNumberType))
If I use the above, the compiler gives no error, but when I write:
string[] names = Enum.GetNames(ContactNumberType)
It says:
ContactNumberType is a type but used like a variable.
While the type of ContactNumberType is Enum, as far as I know, and the argument of method GetNames needs EnumType, so whats the issue with that?

You have to use typeof becuase the GetNames() method takes a parameter of type Type. Keep in mind that providing a type name is not the same as an instance of Type, which is an object that contains the details of that type.
To pass a type as a parameter, you have two basic choices:
Pass a Type instance
Use a generic
The first of these (which many older methods such as Enum.GetNames() does) requires you to get a Type instance from the type identifier, which we can do using the typeof() operator.
The second of these allows you to pass a type name as a parameter to a method or class to make that method or class generic and tends to be used on newer methods (generics were introduced in .NET 2.0):
var items = someList.OfType<SomeTypeName>();
Enum, however, doesn't have a generic form of GetNames() that allows this, though you could create something like one:
public static class EnumHelper
{
public static string[] GetNames<T>() where T : struct
{
return Enum.GetNames(typeof(T))
}
}
Which you could then call like:
string[] names = EnumHelper.GetNames<ContactNumberType>();

GetNames takes a parameter of type Type. The issue is that ContactNumberType is not a Type object. When you use the typeof operator, it returns the appropriate Type object.

Because typeof operator returns an object of Type

Related

C# Getting Type out of a string variable and using it in generic method

I want to be able to get the actual Type of a string value I receive by some means (i.e from database) so I can use that Type in generic method like DoSomething<Type>().
In my project, I have classes Plane, and Car located in MyCompany.MySolution.Vehicle namespace like so
- MyCompany.MySolution.Vehicle
|+Interfaces
|-Implementations
|-Car
|-Plane
I receive type of the vehicle as a string. So, I get string "Car" which means, I need to get Type Car so I can use that type in a generic method to register it like so:
MyFactory.Register<Car>(carId)
So, MyFactory is static class calling Register() method.
Similarly, I receive string "Plane" which means, I need to get Type Plane so I can use that type in the generic method above to register a Plane.
I tried using something like
MyFactory.Register<Type.GetType("MyCompany.MySolution.Vehicle.Implementations.Car")>(carId)
,but that does not work.
If you want to invoke a Generic Method with a Type parameter generate at Runtime, you could do something like this:
var vehicleString = "Car";
// use the fully-qualified name of the type here
// (assuming Car is in the same assembly as this code,
// if not add a ", TargetAssemblyName" to the end of the string)
var vehicleType =
Type.GetType($"MyCompany.MySolution.Vehicle.Implementations.{vehicleString}");
// assuming MyFactory is the name of the class
// containing the Register<T>-Method
typeof(MyFactory).GetMethod("Register")
.MakeGenericMethod(vehicleType)
.Invoke(this);
Working Example
Just as a note:
This is not how generics are supposed to be used. I'm just pointing out the possibility, not giving you an ideal answer to the problem you're proposing. Maybe you should rethink some of your architectural design choices!
If Register<T> does something like this
void Register<T>(int id)
{
_dictionary.Add(typeof(T), ...);
}
Create a non generic overload
void Register(Type t, int id)
{
_dictionary.Add(t, ...);
}
This new overload is not type safe, but creating a type out of a string isn't anyway.
The purpose of generics is to gain variability (not to be confused with dynamic behavior!) while keeping type safety. But when types are determined at runtime, type safety is not given and generics are more of a hindrance than useful.
Note that type safety is ensured by the compiler, which does of course not work at runtime.
You can use a dictionary which holds all your types with strings keys:
var d = new Dictionary<String,Type>();
d.Add("Car",typeof(Car));
d.Add("Plane",typeof(Plane));
Then if you get the string "Car" from the database you can get the type like this:
var myType = d["Car"];
Then use myType as the real Type.

Why does a method that returns a type result in an implicit typing of dynamic?

In the following code snippet why does the implicitly typed variable be determined as a dynamic instead of the method's return type of FluentClass?
public static class DynamicTest
{
public class FluentClass
{
public FluentClass SomeMethod(dynamic arg)
{
return this;
}
}
public static void Main()
{
dynamic data = new { Data = 1 };
var fluentClass = new FluentClass();
// fluentClass variable is typed FluentClass
var methodResult = fluentClass.SomeMethod(data);
// methodResult variable is typed dynamic
}
}
Why does a method that returns a type result in an implicit typing of dynamic?
Because that's the best the compiler can do, given the information it has.
The reason methodResult is dynamic is that the entire expression used to initialize it is dynamic. And that's the case, because data is dynamic.
When you use dynamic, you're telling the compiler to not resolve types at compiler time. Instead, they should be resolved according to the normal compiler rules, but at run-time.
The fluentClass variable could hold some implementation of FluentClass that contains an overload that matches the run-time type of the argument data. In that case, a different implementation of SomeMethod() could be called, returning a different type.
You've told the compiler to defer type resolution to run-time, so it can't force things back into a strongly-typed context unless you tell it explicitly what type things are. In your example, it can't, so the type remains dynamic.
Note that you might have thought that the compiler would identify the one overload you've provided, based on its parameter type of dynamic. But that's not how dynamic works. The dynamic parameter affects only the implementation of the method, i.e. the code in its body. As far as calling the method goes, the parameter is essentially object. It's just that when the parameter value is used in the method body, it has the features of dynamic.
Another way to think of dynamic is that it accepts any object as input (like object), but then allows you to use any member of that object that you believe exists (if it doesn't exist an exception will be thrown at run-time). Using dynamic defers the compiler logic downstream, i.e. for the output of any usages of the dynamic variable, but doesn't affect the input, i.e. the assignment of that variable.
Note also that even if the method call is completely unambiguous, e.g. a static method where there's only one method with that name, you'll still get a dynamic result. Once you start using dynamic, it sticks with you until you provide an explicit cast to get back to a known type.
Related reading:
Very similar to your question, if not actually duplicates:
Why does a method invocation expression have type dynamic even when there is only one possible return type?
Why does this method keep returning dynamic despite the return type in the signature?
Why doesn't this string.Format() return string, but dynamic?
More general discussion of dynamic:
What is the 'dynamic' type in C# 4.0 used for?
C# 4: Real-World Example of Dynamic Types

Can't omit the extension type argument when calling generic extension method with mutually constrained type parameters

public static class Utility {
public static void ShadowDeserializeFile<T, S>(this T target, FileInfo file)
where T : ShadowDeserializable<S> {
S shadow = SomeHelpingMethod(file);
target.ShadowDeserialize(shadow);
}
}
public interface ShadowDeserializable<S> {
void ShadowDeserialize(S shadow);
}
With above code I expect I can call it like:
var something = new SomeType(); //SomeType implements ShadowDeserializable<ShadowType>
something.ShadowDeserializeFile<ShadowType>(aFileInfoObj);
However Visual Studio issues error saying that using the generic method requires 2 type arguments. Only when calling as below it compiles:
something.ShadowDeserializeFile<SomeType,ShadowType>(aFileInfoObj);
I tried switching the order of type parameters in the method declaration, no difference.
How should I modify the declaration so that it could be called concisely as I expected?
Or is my expectation simply wrong as the extension type argument simply can't be omitted in this case?
There is no way to infer type of one parameter and specify another explicitly.You need to specify both types.Another option is to add a parameter of type S and then compiler will infer the second parameter's type for you based on what you pass to the method.Then you can call it without specifying any type. But if you don't need such parameter, specifying two types is the only option.
If specifying one parameter where two type is expected would be possible, it would cause ambiguity.Imagine what would happen if you have another method with the same name that has one generic argument.

c# Generics: Passing List<string> to a method that expects a List<T>

I've had my first foray into generics, and understand them a little bit. I have a method intended to accept two lists of any object, match them various ways and return the matched/unmatched objects (the stuff inside the method probably isn't key here). The purpose is to accept any kind of object, be it customers, or whatever. However, I've hit a snag with getting it to accept 'string', I'm guessing because it's not initialised with the new() keyword and isn't like a normal instanced class.
So, I have a method declaration like so:
public static compareResult<T> stepCompare<T>(List<T> leftList, List<T> rightList, Comparison<T> IDComparer = null, Comparison<T> lowLevelComparer = null, bool confirmUniqueness = true) where T : IComparable, new()
Admittedly, adding the where clause at the end was in response to an error "cannot create an instance of the variable type 'T' because it does not have the new() constraint". This appeared against a line in the method saying
T lastItem = new T();
However, now if I try to pass it two Lists<string>, it says "'string' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'MF.Comparers.stepCompare<T>(System.Collections.Generic.List<T>, System.Collections.Generic.List<T>, System.Comparison<T>, System.Comparison<T>, bool)'...
Any way to let this method accept lists whether they be of string or other classes? Or a shortcut to put lists of string into a type that will be accepted?
You can't make string satisfy the new() constraint, no. While string is a normal class, and instances can be created using constructors in a perfectly normal way, it doesn't have a parameterless constructor.
The best approach really depends on why you had that line of code including lastItem. If you just want some default value, then default(T) is probably the best approach.
If you really do want to create a new instance of T, then you should probably accept a Func<T> in the method's parameter list, as a way of creating a default value on demand. Alternatively, if you're happy using a particular single value as the default, you could just add a parameter of type T. It's hard to say without seeing the rest of your code.
If you want any object, you probably have to live without the new T(). You could do the same with a combination of reflection, special-cases (for string etc), and Activator.CreateInstance<T>() - however, IMO you should limit yourself (in this case) to default(T), which will be null for reference types (including string) and nullable value-types, and all-zeros for non-nullable value-types. You should also probably use a bool or similar to make sure you don't actually use that value, except to satisfy definite assignment rules for the compiler.

If A<T1,T2> is a template for actual type, then why is typeof(A<,>) allowed?

class Program
{
static void Main(string[] args)
{
Type t = typeof(A<,>);
Console.WriteLine(typeof(A<,>)); // prints A'2[T1,T2]
}
}
class A<T1,T2>
{
}
As far as I know, generic type A<T1, T2> is not an actual type, but rather a blueprint/template for an actual type, so why does typeof accept it as a parameter (since as far as I know, typeof accepts as parameter actual types)?
Thank you
In reflection the unconstructed generic type, say C<> is conflated with the instance type C<T>.
This is perhaps less than theoretically pure; I think of these as very different entities. I think of one as the symbol "C with one type parameter" and the other as a compile time type C<T>. In code, C<> and C<T> are not synonyms for each other; you can make a field of the latter type if T is in scope, but you cannot ever make a field of the former type.
That the reflection library gives you the type of the instance type when you ask for the unconstructed type is not all bad though. What would you do with the unconstructed type? There's nothing you really can do with it. But with the instance type, you can say "substitute int for T" in here.
The real benefit of getting C<T> when you ask for typeof(C<>) is that this always gives you the unconstructed type. Compare:
class C<T>
{
public static Type CT() { return typeof(C<T>); }
public static Type JustC() { return typeof(C<>); }
}
When you call CT, what are you going to call it on? There's no type C<T> to call CT on. You can call C<int>.CT in which case you'll get back C<int>, not C<T>. The only way to get the type C<> constructed with T is to ask for typeof(C<>).
Does that make sense?
I haven't yet covered reflection ( I have a vague idea of what it is )
Reflection is simply the library of code that allows you to get information about your code in the code itself. "typeof" gives you a Type object which you can then "reflect" upon to find out information about the type.
I'm not sure I understand what you mean by "even when T is not in scope"
The way I said it was confusing. I've rephrased it.
It is accepted because it is a generic type.
It is an open generic type (where they type parameters have not been specified), but a type none the less.
See the discussion here (What exactly is an “open generic type”).
And on MSDN (typeof):
The typeof operator can also be used on open generic types.
Because A<T1, T2> is an open generic, which the documentation explicitly says it supports.

Categories

Resources