I want to build a method that accepts parameter as Type like
void M1(Type t)
{
// check which type it is
}
and call it like
M1(typeof(int));
I have no idea how to check type in method body.
I have tried
if (t is double)
But it is giving warning
The given expression never provided type (double)
Please help me for checking the type of parameter.
If you want to check for an exact type, you can use:
if (t == typeof(double))
That's fine for double, given that it's a struct, so can't be inherited from.
If you want to perform a more is-like check - e.g. to check whether a type is compatible with System.IO.Stream - you can use Type.IsAssignableFrom:
if (typeof(Stream).IsAssignableFrom(t))
That will match if t is System.IO.MemoryStream, for example (or if it's System.IO.Stream itself).
I always find myself having to think slightly carefully to work out which way round the call goes, but the target of the call is usually a typeof expression.
You can try
if(t == typeof(double))
or
if (typeof(double).IsAssignableFrom(t))
or
if(t == default(double).GetType())
or
if(t.Name == "Double")
Personally i prefer the first option
Have a look at IsAssignableFrom, which determines whether an instance of a specified type can be assigned to the current type instance.
public void M<T>(T value)
{
if (typeof(T).IsAssignableFrom(typeof(double)))
Console.Write("It's a double");
}
It returns true if the given parameter:
represents the same type.
is derived either directly or indirectly from the current instance.
is a generic type parameter, and the current instance represents one of the constraints of the parameter.
represents a value type, and the current instance represents Nullable (Nullable(Of paramerter) in Visual Basic).
Related
In WinRT, settings are stored as objects which means that you end up doing a lot of casting to get back to the type you want. Since that seems to map onto one of the reasons why generics were added to C#, I've been trying to simplify my code so that I can do something like:
public string LastRunVersion
{
get
{
return GetLocalSettingsValue<String>("LastRunVersion", null);
}
set
{
SetLocalSettingsValue("LastRunVersion", value);
}
}
The problem I'm having is with the signature for SetLocalSettingsValue. I tried:
private T GetLocalSettingsValue<T>(string tag, T defaultValue) where T:Object
but Object isn't allowed because it isn't a valid constraint. I know that I only store booleans and strings, so I then tried:
private T GetLocalSettingsValue<T>(string tag, T defaultValue) where T:String, bool
but the compiler says that "A type used as a constraint must be an interface, a non-sealed class or a type parameter".
What do I need to do with the definition in order to allow me to use string and bool?
Thanks.
Implementing two different methods, as Sriram suggests, does seem like the simplest solution for the immediate concern. That said, your generic approach is viable, has precedent, and will make it much easier to extend the code in the future.
In fact, what you tried was nearly correct. The main thing is that you don't actually need a constraint at all. The method declaration is fine without it, and though you don't show the method body, as long as all you need to do is cast some object reference to the type T, that will work:
private T GetLocalSettingsValue<T>(string tag, T defaultValue)
{
object value;
// initialize/retrieve the value somehow
// Check for value present, return default if missing, cast otherwise
return value != null ? (T)value : defaultValue;
}
In fact, since you are passing a default value, type inference will allow you to omit the type parameter in some cases. For example:
public string LastRunVersion
{
get { return GetLocalSettingsValue("LastRunVersion", (string)null); }
}
If you had a non-null default value, the above would be more interesting. :) With the null value, you have to cast it to string just for the compiler to know what the correct type is, which is practically the same as just providing the type parameter. But if you were passing a string literal or the value of a string variable, the type would be clear and the name of the type would not need to be provided at all (not even as a cast).
More interesting is the bool scenario:
public string LastRunVersion
{
get { return GetLocalSettingsValue("SomeBooleanSetting", false); }
}
Here, the literal has a clear type, and so you don't need to provide the type name in any form.
Finally, note that C# does have the idea of default values for types. If you want to support non-null, non-zero default values, then your current approach is good. However, if your defaults are always going to be things like null, false, or 0 (e.g. for an int, should you ever need to store something like that), then you don't need the default parameter at all:
private T GetLocalSettingsValue<T>(string tag)
{
object value;
// initialize/retrieve the value somehow
// Check for value present, return default if missing, cast otherwise
return value != null ? (T)value : default(T);
}
Any reference type will use null as the default. For value types, you will get whatever the value would be if you created an instance using the parameterless constructor (all value types have a parameterless constructor). Numeric types all default to their version of 0, bool defaults to false, etc.
Naturally, in that case you will always have to provide the type parameter, since there aren't any arguments from which the type parameter could be inferred.
public T getValueByName<T>(String name)
{
if( T is List )
Object containedType = T.WhatGoesHere()?
...
In the above code, I need to know if I can convert a List to whatever type of list is passed in, e.g., List<Control>.
Is there a way to interrogate the generic for the contained type? I could get List<Control>, List<String>, List<Form> etc..
I could split the API to return lists in a separate method where the contained type is passed in, thus requiring the caller to use one method for lists and one for simple types. Either way they have to know what's coming back, but if there's a smooth way to do what I'm asking about, I'd rather keep the API simple.
Note: this is a solution to the lack of covariance because even though there is an implicit conversion operator defined on the contained type, a cast of List to T fails. So, in order to follow the solution listOfB.Cast<A>(); from here, I need to know to what to cast (what is A).
Thanks!
You can start with typeof(T) to get an instance of System.Type that represents T.
Once you have that, you can check Type.IsGenericType to see if it really is a generic and then call Type.GetGenericArguments() to see what generic arguments were used.
For example, if T was List<int> IsGenericType would be true and GetGenericArguments() would return an array containing one element: System.Int32
For example, here is a snippet of code I wrote to see if a given type (variable type) is some implementation if IEnumerable<T> where T is not known. It first has to see if it is a generic, then work out whether it has only one argument, determine said argument and see if it implements the interface, given that argument:
if (type.IsGenericType)
{
Type[] genericArguments = type.GetGenericArguments();
if (genericArguments.Length == 1)
{
Type proposedEnumerable = typeof(IEnumerable<>).MakeGenericType(genericArguments);
if (proposedEnumerable.IsAssignableFrom(type))
{
For reference, see:
http://msdn.microsoft.com/en-us/library/system.type.isgenerictype(v=vs.110).aspx
http://msdn.microsoft.com/en-us/library/system.type.getgenericarguments(v=vs.110).aspx
Given a collection
IEnumerable<Type> supportedTypes
What's the best way to check whether a given object is one of those types (or a derived type)?
My first instinct was to do something like:
// object target is a parameter passed to the method in which I'm doing this.
if (supportedTypes.Count( supportedType => target is supportedType ) > 0)
{
// Yay my object is of a supported type!!!
}
..but that doesn't seem to be working. Can I not use the "is" keyword in a lambda expression like this?
OK so in the course of typing the question and doing some more experimenting to make sure I wasn't asking something really stupid, I realized an easy solution. Posting here in case somebody else ever does something equally stupid. ;-)
You can't use the "is" keyword in your lambda expression, but you can use:
supportedType => supportedType.IsInstanceOfType(target)
yielding:
if (supportedTypes.Count( supportedType =>
supportedType.IsInstanceOfType(target)) > 0)
if (supportedTypes.Any( supportedType =>
supportedType.IsInstanceOfType(target)))
// object target is a parameter passed to the method in which I'm doing this.
{
// Yay my object is of a supported type!!!
}
hat-tip to Bob Vale for noting in the comments below that I should have been using .Any(...) rather than .Count(...) > 0
Why don't you use Contains and target.GetType?
bool ar isSupported = supportedTypes.Contains(target.GetType());
or Any
bool isSupported = supportedTypes.Any(t => t == target.GetType());
(don't use Enumerable.Count if you just want to know if a sequence contains a matching element, that is rather inefficient if the sequnce is large or the predicate is expensive)
Edit: If you want to take inheritance into account you can use Type.IsAssignableFrom:
var isSupported = supportedTypes.Any(t => target.GetType().IsAssignableFrom(t));
The is operator is used to check whether an instance is compatible to a given type.
The IsAssignableFrom method is used to check whether a Type is compatible with a given type.
Determines whether an instance of the current Type can be assigned
from an instance of the specified Type.
I'm a newer in c# so maybe my question will seem naive to some of you.
I'm using this method:
public static object ChangeType(object value, Type conversionType);
From metadata manual:
Returns:
An object whose type is conversionType and whose value is equivalent
to value.-or-A
null reference (Nothing in Visual Basic), if value is null and conversionType
is not a value type.
But in method signature the returned type always 'object'. So, what is the benefit in converting the value if returned type is object?
Convert.ChangeType creates a new object of the specified type, with a value equivalent to the object you passed.
For example, Convert.ChangeType("42", typeof(int)) will return a boxed int instance rather than a string.
The actual behavior is completely within the IConvertible implementation of the object you pass.
The reason is that you can cast to your particular type. This method comes from before generic types so the only way it could return one of any number of types is by returning the supertype of all of them, ie object. You can of course then cast that to your chosen type and guarantee you will be successful but the only other option would be an overload of every single type ever which would be a bit weighty. :)
The thing to note is that this isn't just the same as casting. It will return a whole new object which is the type you asked for rather than the type you gave it.
Also,
from the msdn documentation: http://msdn.microsoft.com/en-us/library/aa324833(v=vs.71).aspx
*
value An Object that implements the IConvertible interface.
*
In .net methods have a fixed signature (with generics you can go further, but that's not the case here) - so for this conversion method they chose the most common type: object.
Consider Person and Man. Man is defined as
class Man : Person
In order to create an address book, you would not create two methods:
Man GetByName(string name);
Woman GetByName(string name);
Instead you would create one method:
Person GetByName(string name);
This method would return a Person and even though the actual object returned is a Man, all you currently know about it is that it's a Person.
Back to the converter: you know the return type as you supplied it in the parameters, but a long time ago when the method was created they did not know what you were going to supply as parameter. You can safely cast the result to the type you already know:
MyType myObject = (MyType)ChangeType(value, typeof(MyType));
This question already has answers here:
Type Checking: typeof, GetType, or is?
(15 answers)
Closed 1 year ago.
Which one is the preferred way to get the type?
You can only use typeof() when you know that type at compile time, and you're trying to obtain the corresponding Type object. (Although the type could be a generic type parameter, e.g. typeof(T) within a class with a type parameter T.) There don't need to be any instances of that type available to use typeof. The operand for typeof is always the name of a type or type parameter. It can't be a variable or anything like that.
Now compare that with object.GetType(). That will get the actual type of the object it's called on. This means:
You don't need to know the type at compile time (and usually you don't)
You do need there to be an instance of the type (as otherwise you have nothing to call GetType on)
The actual type doesn't need to be accessible to your code - for example, it could be an internal type in a different assembly
One odd point: GetType will give unexpected answers on nullable value types due to the way that boxing works. A call to GetType will always involve boxing any value type, including a nullable value type, and the boxed value of a nullable value type is either a null reference or a reference to an instance of a non-nullable value type.
GetType() works at runtime, typeof() is a compile-time operator.
So,
// untested, schematic
void ShowType(Object x)
{
Write(x.GetType().Name); // depends on actual type
// typeof(x) won't actually compile
Write(typeof(x).Name); // always System.Object
}
ShowType("test");
Will print System.String and System.Object.
See this question for a better example.
GetType is a virtual method on Object - this means given an instance of a class, you can retrieve the corresponding Type object.
typeof is a C# operator - this is used to perform a compile time lookup i.e. Given a Symbol representing a Class name, retrieve the Type object for it.
if (typeof(String) == "test".GetType())
It's not exactly the same, and the problem appears when you use
inheritance.
I.e.:
WebPage1 inherits from Page, and this one inherits also from Object, so if you test for (new WebPage1()).GetType() == typeof(object) it'll return false because the types are diferent, but when you test using the is operator it's true.
((new WebPage1()) is object) is true because (new WebPage1()) is an object of type WebPage1, and also a Page and an object.
The types might be different, but is checks if you can cast safely to
this type.