I have a query about type of null.
I have a small program can anyone tell me about this.
public class TestApplication
{
public void ShowText(object ob)
{
Console.Write("Inside object");
}
public void ShowText(string str)
{
Console.Write("Inside string");
}
public void ShowText(int i)
{
Console.Write("Inside int.");
}
public void ShowText(char c)
{
Console.Write("Inside Character");
}
static void Main(string[] args)
{
new TestApplication().ShowText(null);
Console.Read();
}
}
Why it call the string function.
Is it means the type of null is string.
It might look a foolish conclusion but I am not able to find the region why it is calling the function of string.
Your question about the type of the null literal is answered here: What is the type of null literal?
But that doesn't really matter when talking about overload resolution. The actual null value itself will automatically be converted to whatever type it ends up as.
As for why the string overload is called:
You can't pass null as int and char parameters as they're value types, so those two overloads are out. (They could have been candidates had you made them nullable int? and char? types, but I won't go into that.)
Between the two other overloads taking reference types, string is a more specific type than object. That is, it derives from (and is therefore implicitly convertible to) object. Further, from the following section in the C# language spec (emphasis mine):
7.5.3.5 Better conversion target
Given two different types T1 and T2, T1 is a better conversion target than T2 if at least one of the following holds:
An implicit conversion from T1 to T2 exists, and no implicit conversion from T2 to T1 exists
...
Thus, the string overload is chosen as the best fit.
null can fit to any reference-type. and hence is a very good example for polymorphism.
lets say you have a Vehicle class. you create three more class Two-Wheeler, Three-Wheeler, Four-Wheeler.
if latter 3 class extends Vehicle class; it is called Vehicle is specified into those three categories.
So, given a value, say car, more specific fit to this value is Four-Wheeler.
Similar is the case with null. it can fit to either Object OR String; but more specific match is String.
Lets see how compiler thinks (specific to your code only) when it sees a call to ShowText(null) method
Find ShowText method.
Oh, I've found 4, methods, which one to call?!!
Lets see what argument is passed, hmm .. it's null.
Find ShowText method which has reference type as argument. all overloads with primitive arguments are ignored.
Oh No ... i can match it to eithe string OR object.
Which is more specific. i.e which comes first in inheritance hierarchy from below.
Hurray .. found it .. it's string .. lets call it.
And, for an exercise if you want to undestand that what will happen if compiler finds at step 6 mor than one matches ... define a ShowText(string[] vals) and see yourself.
This is an example of the overload resolution in C#, it does not prove that the type of the null is string.
null is a special value that is included in the domain of any reference type, it basically determines that there is not a valid reference. As such, it can be a string, an int?, an object etc, etc.
You can even cast null to any reference type, to get a "correctly" typed null, e.g. you must cast null if it's used as a value in a ? operator
int? value = (i > 0) ? i : null; // does not compile
int? value = (i > 0) ? i : (int?)null; //works
Related
private static Matcher<T> EqualTo<T>(T item)
{
return new IsEqual<T>(item);
}
How do I modify the above method definition such that the following are valid/allowed.
EqualTo("abc");
EqualTo(4);
EqualTo(null); // doesn't compile. EqualTo<string>(null) does
Trying to port some Java code where null seems to be acceptable value for a T parameter.
Update
Thanks: for all the answers - especially Eamon and Jason. I didn't want the method calls to bother with type-inference. The following overload fixed it.
private static Matcher<object> EqualTo(object item)
{
return EqualTo<object>(item);
}
Actually the above question was a part of a larger puzzle. The end goal was for the following to work.
this.AssertThat(null, EqualTo(null));
this.AssertThat(null, Not(EqualTo("hi")));
this.AssertThat("hi", Not(EqualTo(null)));
Applied the same fix.. RFC. (Ignore the ugly extension method part - that's another problem. Wanted to have these methods in all test-fixtures without inheritance.)
public static void AssertThat<T>(this object testFixture, object actual, Matcher<T> matcher, string message = "")
{
AssertThat(anyObject, (T)actual, matcher, message);
}
public static void AssertThat<T, TSuper>(this object testFixture, T actual, Matcher<TSuper> matcher, string message = "") where T : TSuper
{
... check and assert
Consider the following method:
public bool IsNullString<T>(T item) {
return typeof(T) == typeof(string) && item == null;
}
Yes, this is a pathetically stupid method and using generics is pointless here, but you'll see the point in a moment.
Now consider
bool first = IsNullString<string>(null);
bool second = IsNullString<Foo>(null);
bool third = IsNullString(null);
In the first and second, the compiler can clearly distinguish the type of T (no inference is needed). In the third, how the compiler infer what T is? In particular, it can't distinguish between T == string and T == Foo, or any other type for that matter. Therefore, the compiler has to give you a compile-time error.
If you want to get around this, you either need to cast null
EqualTo((object)null);
or explicitly state the type
EqualTo<object>(null)
or define an overload
private static Matcher<object> EqualTo(object item) {
return new IsEqual<object>(item);
}
Not possible without explicitly specifying a T or doing a cast. Generics are compile time constructs and as such if the compiler can't figure out the type at compile time, then it won't compile (as you're seeing).
Since you can't do exactly what you are wanting to do, how about defining an EqualTo(object) overloaded method? That should allow your required syntax.
You may work around this limitation by using the following syntax:
EqualTo("abc");
EqualTo(4);
EqualTo(default(object));
//equivalently:
EqualTo((object)null);
default(T) is the value a field of type T has if not set. For reference types, it's null, for value types it's essentially memory filled with zero bytes (...which may mean different things for different types, but generally means some version of zero).
I try to avoid the null everywhere in my code nowadays. It hampers type inference elsewhere too, such as with the var declared field and in a ternary operator. For example, myArray==null ? default(int?) : myArray.Length is OK, but myArray==null ? null : myArray.Length won't compile.
Maybe implementing a non-generic EqualTo, which takes an Object as the argument type, would solve the issue of rewriting those code lines.
I have the following code, that I use as sample for illustrating different scenarios:
public static void MethodWithOptionalGuid(Guid id = default(Guid)) { }
public static void MethodWithOptionalInteger(int id = 2) { }
public static void MethodWithOptionalString(string id = "33344aaa") { }
public static void MethodWithoutOptionalParameter(int id, Guid longId) { }
static void Main(string[] args)
{
var methods = typeof(Program).GetMethods(BindingFlags.Public | BindingFlags.Static).ToList();
foreach (var method in methods)
{
PrintMethodDetails(method);
}
Console.ReadLine();
}
static void PrintMethodDetails(MethodInfo method)
{
Console.WriteLine(method.Name);
foreach (var parameter in method.GetParameters().ToList())
{
Console.WriteLine(parameter.Name +
" of type " + parameter.ParameterType.ToString() +
" with default value:" + parameter.DefaultValue);
}
Console.WriteLine();
}
It prints the following:
MethodWithOptionalGuid
id of type System.Guid with default value:
MethodWithOptionalInteger
id of type System.Int32 with default value:2
MethodWithOptionalString
id of type System.String with default value:33344aaa
MethodWithoutOptionalParameter
id of type System.Int32 with default value:
longId of type System.Guid with default value:
The output seems fine for the last 3 methods.
My question is regarding the first one, MethodWithOptionalGuid: why the Guid's default value is not recognized?
I expected to receive something like "0000000-..." . I also tried initializing the optional parameter with new Guid() and same result. I tried as well other structs, like TimeSpan and the behavior is the same.
I expected that all value types would behave the same (as seen in integer example).
Extra: I found this thing while trying to use in Asp.Net MVC an action with an optional Guid parameter and failed (had to make the Guid nullable). Went through MVC code and found that it uses the DefaultValue at some point. So I made this code sample to better illustrate my issue.
The why is pretty relevant and something you really need to heed when you want to do something like this. Dragons live here. If you use ildasm.exe to look at the method then you'll see:
.param [1] = nullref
A null as a default for a structure type, uh-oh. The semantics for the .param directive is described in the CLI spec, Ecma-335, chapter II.15.4.1.4. It is very short, I'll copy-paste the entire chapter (edited for readability)
MethodBodyItem ::= .param ‘[’ Int32 ‘]’ [ ‘=’ FieldInit ]
This directive stores in the metadata a constant value associated with method parameter number Int32,
see §II.22.9. While the CLI requires that a value be supplied for the parameter, some tools can use the
presence of this attribute to indicate that the tool rather than the user is intended to supply the value of
the parameter. Unlike CIL instructions, .param uses index 0 to specify the return value of the method,
index 1 to specify the first parameter of the method, index 2 to specify the second parameter of the
method, and so on.
[Note: The CLI attaches no semantic whatsoever to these values—it is entirely up to compilers to
implement any semantic they wish (e.g., so-called default argument values). end note]
The [Note] is most relevant. When you use Reflection then you play the role of the compiler and it is up to you to interpret the default value correctly. In other words, you have to know that in C# the default value for a structure type is null.
This is otherwise a limitation in what can be stored in a [FieldInit]. The initialization value must be stored in the metadata of the assembly and is subject to the same kind of limitations of an [attribute] declaration. Just simple value types can be used, not structures. So by convention the C# designers worked around this by using null instead. Good enough for the C# compiler to understand that default(Guid) was intended.
That's not where the trouble ends, there are other ways to indicate an optional argument, the [OptionalAttribute] was used prior to C# v4.0. And is still used today, by COM interop libraries and other languages like VB.NET and C++/CLI. That's where the dragons live.
Ignoring those beasts for now, workaround code for what you have could look like this:
var def = parameter.DefaultValue;
if (parameter.ParameterType.IsValueType && def == null) {
def = Activator.CreateInstance(parameter.ParameterType);
}
Console.WriteLine(parameter.Name +
" of type " + parameter.ParameterType.ToString() +
" with default value:" + def);
Open your testfile with a decompiler of your choice and you will see that your code actually get compiled to:
public static void MethodWithOptionalGuid(Guid id = null) { }
This is why the DefaultValue property returns null.
When you use this parameter now, lets say you add:
Console.WriteLine(id);
The compiler will insert a
box [mscorlib]System.Guid
statement before the WriteLine. Now the output will be the expected "0000000-..."
Sorry - I can't tell you WHY it doesn't return the correct value but I've a workarround using this extension method:
public static object GetDefaultValue(this ParameterInfo p)
{
if (!p.Attributes.HasFlag(ParameterAttributes.HasDefault))
{
return null;
}
if (p.DefaultValue != null || p.RawDefaultValue != null)
{
return p.DefaultValue ?? p.RawDefaultValue;
}
return p.ParameterType.IsValueType ? Activator.CreateInstance(p.ParameterType) : null;
}
Maybe it will help.
I guess the answer can be found in c# language specifications (someone may find something more relevant)
Point 4.1.2
When the operands of an expression are all simple type constants, it
is possible for the compiler to evaluate the expression at
compile-time. Such an expression is known as a constant-expression
(§7.19). Expressions involving operators defined by other struct types
are not considered to be constant expressions.
Through const declarations it is possible to declare constants of the
simple types (§10.4). It is not possible to have constants of other
struct types, but a similar effect is provided by static readonly
fields.
Even if we're not talking about expressions or consts here, it seems that only simple types (structs like int) can be evaluated /computed at compile time. That's why default(int) can be evaluated and then would display 0 in your code.
But other struct can't be computed at compile time, so I would say that it's the reason why they're evaluated to null.
When you set a default parameter value, it has to be a compile-time constant.
The tricky part is that you can put default(Guid) or new Guid() as an accepted compile-time constant (BUT evaluated to null), but... it can't be a const.
For example, you could not do
const Guid g = new Guid();
Consider the following code:
void Handler(object o, EventArgs e)
{
// I swear o is a string
string s = (string)o; // 1
//-OR-
string s = o as string; // 2
// -OR-
string s = o.ToString(); // 3
}
What is the difference between the three types of casting (okay, the 3rd one is not a casting, but you get the intent). Which one should be preferred?
string s = (string)o; // 1
Throws InvalidCastException if o is not a string. Otherwise, assigns o to s, even if o is null.
string s = o as string; // 2
Assigns null to s if o is not a string or if o is null. For this reason, you cannot use it with value types (the operator could never return null in that case). Otherwise, assigns o to s.
string s = o.ToString(); // 3
Causes a NullReferenceException if o is null. Assigns whatever o.ToString() returns to s, no matter what type o is.
Use 1 for most conversions - it's simple and straightforward. I tend to almost never use 2 since if something is not the right type, I usually expect an exception to occur. I have only seen a need for this return-null type of functionality with badly designed libraries which use error codes (e.g. return null = error, instead of using exceptions).
3 is not a cast and is just a method invocation. Use it for when you need the string representation of a non-string object.
string s = (string)o; Use when something should
definitely be the other thing.
string s = o as string; Use when something might be the other
thing.
string s = o.ToString(); Use when you don't care what
it is but you just want to use the
available string representation.
It really depends on whether you know if o is a string and what you want to do with it. If your comment means that o really really is a string, I'd prefer the straight (string)o cast - it's unlikely to fail.
The biggest advantage of using the straight cast is that when it fails, you get an InvalidCastException, which tells you pretty much what went wrong.
With the as operator, if o isn't a string, s is set to null, which is handy if you're unsure and want to test s:
string s = o as string;
if ( s == null )
{
// well that's not good!
gotoPlanB();
}
However, if you don't perform that test, you'll use s later and have a NullReferenceException thrown. These tend to be more common and a lot harder to track down once they happens out in the wild, as nearly every line dereferences a variable and may throw one. On the other hand, if you're trying to cast to a value type (any primitive, or structs such as DateTime), you have to use the straight cast - the as won't work.
In the special case of converting to a string, every object has a ToString, so your third method may be okay if o isn't null and you think the ToString method might do what you want.
'as' is based on 'is', which is a keyword that checks at runtime if the object is polimorphycally compatible (basically if a cast can be made) and returns null if the check fails.
These two are equivalent:
Using 'as':
string s = o as string;
Using 'is':
if(o is string)
s = o;
else
s = null;
On the contrary, the c-style cast is made also at runtime, but throws an exception if the cast cannot be made.
Just to add an important fact:
The 'as' keyword only works with reference types. You cannot do:
// I swear i is an int
int number = i as int;
In those cases you have to use casting.
If you already know what type it can cast to, use a C-style cast:
var o = (string) iKnowThisIsAString;
Note that only with a C-style cast can you perform explicit type coercion.
If you don't know whether it's the desired type and you're going to use it if it is, use as keyword:
var s = o as string;
if (s != null) return s.Replace("_","-");
//or for early return:
if (s==null) return;
Note that as will not call any type conversion operators. It will only be non-null if the object is not null and natively of the specified type.
Use ToString() to get a human-readable string representation of any object, even if it can't cast to string.
The as keyword is good in asp.net when you use the FindControl method.
Hyperlink link = this.FindControl("linkid") as Hyperlink;
if (link != null)
{
...
}
This means you can operate on the typed variable rather then having to then cast it from object like you would with a direct cast:
object linkObj = this.FindControl("linkid");
if (link != null)
{
Hyperlink link = (Hyperlink)linkObj;
}
It's not a huge thing, but it saves lines of code and variable assignment, plus it's more readable
According to experiments run on this page: http://www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as
(this page is having some "illegal referrer" errors show up sometimes, so just refresh if it does)
Conclusion is, the "as" operator is normally faster than a cast. Sometimes by many times faster, sometimes just barely faster.
I peronsonally thing "as" is also more readable.
So, since it is both faster and "safer" (wont throw exception), and possibly easier to read, I recommend using "as" all the time.
2 is useful for casting to a derived type.
Suppose a is an Animal:
b = a as Badger;
c = a as Cow;
if (b != null)
b.EatSnails();
else if (c != null)
c.EatGrass();
will get a fed with a minimum of casts.
"(string)o" will result in an InvalidCastException as there's no direct cast.
"o as string" will result in s being a null reference, rather than an exception being thrown.
"o.ToString()" isn't a cast of any sort per-se, it's a method that's implemented by object, and thus in one way or another, by every class in .net that "does something" with the instance of the class it's called on and returns a string.
Don't forget that for converting to string, there's also Convert.ToString(someType instanceOfThatType) where someType is one of a set of types, essentially the frameworks base types.
It seems the two of them are conceptually different.
Direct Casting
Types don't have to be strictly related. It comes in all types of flavors.
Custom implicit/explicit casting: Usually a new object is created.
Value Type Implicit: Copy without losing information.
Value Type Explicit: Copy and information might be lost.
IS-A relationship: Change reference type, otherwise throws exception.
Same type: 'Casting is redundant'.
It feels like the object is going to be converted into something else.
AS operator
Types have a direct relationship. As in:
Reference Types: IS-A relationship Objects are always the same, just the reference changes.
Value Types: Copy boxing and nullable types.
It feels like the you are going to handle the object in a different way.
Samples and IL
class TypeA
{
public int value;
}
class TypeB
{
public int number;
public static explicit operator TypeB(TypeA v)
{
return new TypeB() { number = v.value };
}
}
class TypeC : TypeB { }
interface IFoo { }
class TypeD : TypeA, IFoo { }
void Run()
{
TypeA customTypeA = new TypeD() { value = 10 };
long longValue = long.MaxValue;
int intValue = int.MaxValue;
// Casting
TypeB typeB = (TypeB)customTypeA; // custom explicit casting -- IL: call class ConsoleApp1.Program/TypeB ConsoleApp1.Program/TypeB::op_Explicit(class ConsoleApp1.Program/TypeA)
IFoo foo = (IFoo)customTypeA; // is-a reference -- IL: castclass ConsoleApp1.Program/IFoo
int loseValue = (int)longValue; // explicit -- IL: conv.i4
long dontLose = intValue; // implict -- IL: conv.i8
// AS
int? wraps = intValue as int?; // nullable wrapper -- IL: call instance void valuetype [System.Runtime]System.Nullable`1<int32>::.ctor(!0)
object o1 = intValue as object; // box -- IL: box [System.Runtime]System.Int32
TypeD d1 = customTypeA as TypeD; // reference conversion -- IL: isinst ConsoleApp1.Program/TypeD
IFoo f1 = customTypeA as IFoo; // reference conversion -- IL: isinst ConsoleApp1.Program/IFoo
//TypeC d = customTypeA as TypeC; // wouldn't compile
}
All given answers are good, if i might add something:
To directly use string's methods and properties (e.g. ToLower) you can't write:
(string)o.ToLower(); // won't compile
you can only write:
((string)o).ToLower();
but you could write instead:
(o as string).ToLower();
The as option is more readable (at least to my opinion).
string s = o as string; // 2
Is prefered, as it avoids the performance penalty of double casting.
I would like to attract attention to the following specifics of the as operator:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/as
Note that the as operator performs only reference conversions,
nullable conversions, and boxing conversions. The as operator can't
perform other conversions, such as user-defined conversions, which
should instead be performed by using cast expressions.
Use direct cast string s = (string) o; if in the logical context of your app string is the only valid type. With this approach, you will get InvalidCastException and implement the principle of Fail-fast. Your logic will be protected from passing the invalid type further or get NullReferenceException if used as operator.
If the logic expects several different types cast string s = o as string; and check it on null or use is operator.
New cool feature have appeared in C# 7.0 to simplify cast and check is a Pattern matching:
if(o is string s)
{
// Use string variable s
}
or
switch (o)
{
case int i:
// Use int variable i
break;
case string s:
// Use string variable s
break;
}
When trying to get the string representation of anything (of any type) that could potentially be null, I prefer the below line of code. It's compact, it invokes ToString(), and it correctly handles nulls. If o is null, s will contain String.Empty.
String s = String.Concat(o);
Since nobody mentioned it, the closest to instanceOf to Java by keyword is this:
obj.GetType().IsInstanceOfType(otherObj)
This question already has answers here:
Is casting the same thing as converting?
(11 answers)
Closed 9 years ago.
I have been working on some code for a while. And I had a question: What's the difference among casting, parsing and converting? And when we can use them?
Casting is when you take a variable of one type and change it to a different type. You can only do that in some cases, like so:
string str = "Hello";
object o = str;
string str2 = (string)o; // <-- This is casting
Casting does not change the variable's value - the value remains of the same type (the string "Hello").
Converting is when you take a value from one type and convert it to a different type:
double d = 5.5;
int i = (int)d; // <---- d was converted to an integer
Note that in this case, the conversion was done in the form of casting.
Parsing is taking a string and converting it to a different type by understanding its content. For instance, converting the string "123" to the number 123, or the string "Saturday, September 22nd" to a DateTime.
Casting: Telling the compiler that an object is really something else without changing it (though some data loss may be incurred).
object obj_s= "12345";
string str_i = (string) obj; // "12345" as string, explicit
int small = 12345;
long big = 0;
big = small; // 12345 as long, implicit
Parsing: Telling the program to interpret (on runtime) a string.
string int_s = "12345";
int i = int.Parse(int_s); // 12345 as int
Converting: Telling the program to use built in methods to try to change type for what may be not simply interchangeable.
double dub = 123.45;
int i = System.Convert.ToInt32(dub); // 123 as int
These are three terms each with specific uses:
casting - changing one type to another. In order to do this, the
types must be compatible: int -> object; IList<T> -> IEnumerable<T>
parsing - typically refers to reading strings and extracting useful parts
converting - similar to casting, but typically a conversion would involve changing one type to an otherwise non-compatible type. An example of that would be converting objects to strings.
A cast from one type to another requires some form of compatibility, usually via inheritance or implementation of an interface. Casting can be implicit or explicit:
class Foo : IFoo {
// implementations
}
// implicit cast
public IFoo GetFoo() {
return Foo;
}
// explicit cast
public IFoo GetFoo() {
return Foo as IFoo;
}
There are quite a few ways to parse. We read about XML parsing; some types have Parse and TryParse methods; and then there are times we need to parse strings or other types to extract the 'stuff we care about'.
int.Parse("3") // returns an integer value of 3
int.TryParse("foo", out intVal) // return true if the string could be parsed; otherwise false
Converting may entail changing one type into another incompatible one. This could involve some parsing as well. Conversion examples would usually be, IMO, very much tied to specific contexts.
casting
(casting to work the types need to be compatible)
Converting between data types can be done explicitly using a cast
static void _Casting()
{
int i = 10;
float f = 0;
f = i; // An implicit conversion, no data will be lost.
f = 0.5F;
i = (int)f; // An explicit conversion. Information will be lost.
}
parsing (Parsing is conversion between different types:)
converts one type to another type can be called as parsing uisng int.parse
int num = int.Parse("500");
traversing through data items like XML can be also called as parsing
When user-defined conversions get involved, this usually entails returning a different object/value. user-defined conversions usually exist between value types rather than reference types, so this is rarely an issue.
converting
Using the Convert-class actually just helps you parse it
for more please refer http://msdn.microsoft.com/en-us/library/ms228360%28VS.80%29.aspx
This question is actually pretty complicated...
Normally, a cast just tells the runtime to change one type to another. These have to be types that are compatible. For example an int can always be represented as a long so it is OK to cast it to a long. Some casts have side-effects. For example, a float will drop its precision if it is cast to an int. So (int)1.5f will result in int value 1. Casts are usually the fastest way to change the type, because it is a single IL operator. For example, the code:
public void CastExample()
{
int i = 7;
long l = (long)i;
}
Performs the cast by running the IL code:
conv.i8 //convert to 8-byte integer (a.k.a. Int64, a.k.a. long).
A parse is some function that takes in once type and returns another. It is an actual code function, not just an IL operator. This usually takes longer to run, because it runs multiple lines of code.
For example, this code:
public void ParseExample()
{
string s = "7";
long l = long.Parse(s);
}
Runs the IL code:
call int64 [mscorlib]System.Int64::Parse(string)
In other words it calls an actual method. Internally, the Int64 type provides that method:
public static long Parse(String s) {
return Number.ParseInt64(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
}
And Number.Parse:
[System.Security.SecuritySafeCritical] // auto-generated
internal unsafe static Int64 ParseInt64(String value, NumberStyles options, NumberFormatInfo numfmt) {
Byte * numberBufferBytes = stackalloc Byte[NumberBuffer.NumberBufferBytes];
NumberBuffer number = new NumberBuffer(numberBufferBytes);
Int64 i = 0;
StringToNumber(value, options, ref number, numfmt, false);
if ((options & NumberStyles.AllowHexSpecifier) != 0) {
if (!HexNumberToInt64(ref number, ref i)) {
throw new OverflowException(Environment.GetResourceString("Overflow_Int64"));
}
}
else {
if (!NumberToInt64(ref number, ref i)) {
throw new OverflowException(Environment.GetResourceString("Overflow_Int64"));
}
}
return i;
}
And so on... so you can see it is actually doing a lot of code.
Now where things get more complicated is that although a cast is usually the fastest, classes can override the implicit and explicit cast operators. For example, if I write the class:
public class CastableClass
{
public int IntValue { get; set; }
public static explicit operator int(CastableClass castable)
{
return castable.IntValue;
}
}
I have overridden the explicit cast operator for int, so I can now do:
public void OverridedCastExample()
{
CastableClass cc = new CastableClass {IntValue = 7};
int i = (int)cc;
}
Which looks like a normal cast, but in actuality it calls my method that I defined on my class. The IL code is:
call int32 UnitTestProject1.CastableClass::op_Explicit(class UnitTestProject1.CastableClass)
So anyway, you typically want to cast whenever you can. Then parse if you can't.
Casting: or Parsing
A cast explicitly invokes the conversion operator from one type to another.
Casting variables is not simple. A complicated set of rules resolves casts. In some cases data is lost and the cast cannot be reversed. In others an exception is provoked in the execution engine.
int.Parse is a simplest method but it throws exceptions on invalid input.
TryParse
int.TryParse is one of the most useful methods for parsing integers in the C# language. This method works the same way as int.Parse.
int.TryParse has try and catch structure inside. So, it does not throw exceptions
Convert:
Converts a base data type to another base data type.
Convert.ToInt32, along with its siblings Convert.ToInt16 and Convert.ToInt64, is actually a static wrapper method for the int.Parse method.
Using TryParse instead of Convert or Cast is recommended by many programmers.
source:www.dotnetperls.com
Different people use it to mean different things. It need not be true outside .net world, but here is what I have understood in .net context reading Eric Lippert's blogs:
All transformations of types from one form to another can be called conversion. One way of categorizing may be
implicit -
a. representation changing (also called coercion)
int i = 0;
double d = i;
object o = i; // (specifically called boxing conversion)
IConvertible o = i; // (specifically called boxing conversion)
Requires implicit conversion operator, conversion always succeeds (implicit conversion operator should never throw), changes the referential identity of the object being converted.
b. representation preserving (also called implicit reference conversion)
string s = "";
object o = s;
IList<string> l = new List<string>();
Only valid for reference types, never changes the referential identity of the object being converted, conversion always succeeds, guaranteed at compile time, no runtime checks.
explicit (also called casting) -
a. representation changing
int i = 0;
enum e = (enum)i;
object o = i;
i = (int)o; // (specifically called unboxing conversion)
Requires explicit conversion operator, changes the referential identity of the object being converted, conversion may or may not succeed, does runtime check for compatibility.
b. representation preserving (also called explicit reference conversion)
object o = "";
string s = (string)o;
Only valid for reference types, never changes the referential identity of the object being converted, conversion may or may not succeed, does runtime check for compatibility.
While conversions are language level constructs, Parse is a vastly different thing in the sense it's framework level, or in other words they are custom methods written to get an output from an input, like int.Parse which takes in a string and returns an int.
The Type class has a method IsAssignableFrom() that almost works. Unfortunately it only returns true if the two types are the same or the first is in the hierarchy of the second. It says that decimal is not assignable from int, but I'd like a method that would indicate that decimals are assignable from ints, but ints are not always assignable from decimals. The compiler knows this but I need to figure this out at runtime.
Here's a test for an extension method.
[Test]
public void DecimalsShouldReallyBeAssignableFromInts()
{
Assert.IsTrue(typeof(decimal).IsReallyAssignableFrom(typeof(int)));
Assert.IsFalse(typeof(int).IsReallyAssignableFrom(typeof(decimal)));
}
Is there a way to implement IsReallyAssignableFrom() that would work like IsAssignableFrom() but also passes the test case above?
Thanks!
Edit:
This is basically the way it would be used. This example does not compile for me, so I had to set Number to be 0 (instead of 0.0M).
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter)]
public class MyAttribute : Attribute
{
public object Default { get; set; }
}
public class MyClass
{
public MyClass([MyAttribute(Default= 0.0M)] decimal number)
{
Console.WriteLine(number);
}
}
I get this error:
Error 4 An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
There are actually three ways that a type can be “assignable” to another in the sense that you are looking for.
Class hierarchy, interface implementation, covariance and contravariance. This is what .IsAssignableFrom already checks for. (This also includes permissible boxing operations, e.g. int to object or DateTime to ValueType.)
User-defined implicit conversions. This is what all the other answers are referring to. You can retrieve these via Reflection, for example the implicit conversion from int to decimal is a static method that looks like this:
System.Decimal op_Implicit(Int32)
You only need to check the two relevant types (in this case, Int32 and Decimal); if the conversion is not in those, then it doesn’t exist.
Built-in implicit conversions which are defined in the C# language specification. Unfortunately Reflection doesn’t show these. You will have to find them in the specification and copy the assignability rules into your code manually. This includes numeric conversions, e.g. int to long as well as float to double, pointer conversions, nullable conversions (int to int?), and lifted conversions.
Furthermore, a user-defined implicit conversion can be chained with a built-in implicit conversion. For example, if a user-defined implicit conversion exists from int to some type T, then it also doubles as a conversion from short to T. Similarly, T to short doubles as T to int.
This one almost works... it's using Linq expressions:
public static bool IsReallyAssignableFrom(this Type type, Type otherType)
{
if (type.IsAssignableFrom(otherType))
return true;
try
{
var v = Expression.Variable(otherType);
var expr = Expression.Convert(v, type);
return expr.Method == null || expr.Method.Name == "op_Implicit";
}
catch(InvalidOperationException ex)
{
return false;
}
}
The only case that doesn't work is for built-in conversions for primitive types: it incorrectly returns true for conversions that should be explicit (e.g. int to short). I guess you could handle those cases manually, as there is a finite (and rather small) number of them.
I don't really like having to catch an exception to detect invalid conversions, but I don't see any other simple way to do it...
Timwi's answer is really complete, but I feel there's an even simpler way that would get you the same semantics (check "real" assignability), without actually defining yourself what this is.
You can just try the assignment in question and look for an InvalidCastException (I know it's obvious). This way you avoid the hassle of checking the three possible meanings of assignability as Timwi mentioned. Here's a sample using xUnit:
[Fact]
public void DecimalsShouldReallyBeAssignableFromInts()
{
var d = default(decimal);
var i = default(i);
Assert.Throws<InvalidCastException)( () => (int)d);
Assert.DoesNotThrow( () => (decimal)i);
}
What you are looking for is if there's an implicit cast from the one type to the other. I would think that's doable by reflection, though it might be tricky because the implicit cast should be defined as an operator overload which is a static method and I think it could be defined in any class, not just the one that can be implicitly converted.
In order to find out if one type can be assigned to another, you have to look for implicit conversions from one to the other. You can do this with reflection.
As Timwi said, you will also have to know some built-in rules, but those can be hard-coded.
It actually happens to be the case that the decimal type is not "assignable" to the int type, and vice versa. Problems occur when boxing/unboxing gets involved.
Take the example below:
int p = 0;
decimal d = 0m;
object o = d;
object x = p;
// ok
int a = (int)d;
// invalid cast exception
int i = (int)o;
// invalid cast exception
decimal y = (decimal)p;
// compile error
int j = d;
This code looks like it should work, but the type cast from object produces an invalid cast exception, and the last line generates a compile-time error.
The reason the assignment to a works is because the decimal class has an explicit override on the type cast operator to int. There does not exist an implicit type cast operator from decimal to int.
Edit: There does not exist even the implicit operator in reverse. Int32 implements IConvertible, and that is how it converts to decimal
End Edit
In other words, the types are not assignable, but convertible.
You could scan assemblies for explicit type cast operators and IConvertible interfaces, but I get the impression that would not serve you as well as programming for the specific few cases you know you will encounter.
Good luck!