Casting: (Newtype) VS. Object as Newtype

Casting: (NewType) vs. Object as NewType

The former will throw an exception if the source type can't be cast to the target type. The latter will result in sc2 being a null reference, but no exception.

[Edit]

My original answer is certainly the most pronounced difference, but as Eric Lippert points out, it's not the only one. Other differences include:

  • You can't use the 'as' operator to cast to a type that doesn't accept 'null' as a value
  • You can't use 'as' to convert things, like numbers to a different representation (float to int, for example).

And finally, using 'as' vs. the cast operator, you're also saying "I'm not sure if this will succeed."

Should I use (ObjectType) or 'as ObjectType' when casting in c#?

If you wish to avoid any InvalidCastExceptions use

MyObjectType senderAsMyType = sender as MyObjectType;

otherwise use

MyObjectType senderAsMyType = (MyObjectType)sender;

if an InvalidCastException represents a true exceptional situation in your application.

As for performance, I would contend that you would find no discernible difference between the two different kinds of casting. I was interested though so I used Jon Skeet's BenchmarkHelper and achieved results that confirmed my suspicions:

Test:

using System;
using BenchmarkHelper;

class Program
{
static void Main()
{
Object input = "test";
String output = "test";

var results = TestSuite.Create("Casting", input, output)
.Add(cast)
.Add(asCast)
.RunTests()
.ScaleByBest(ScalingMode.VaryDuration);
results.Display(ResultColumns.NameAndDuration | ResultColumns.Score,
results.FindBest());
}

static String cast(Object o)
{
return (String)o;
}

static String asCast(Object o)
{
return o as String;
}

}

Output:

============ Casting ============
cast 30.021 1.00
asCast 30.153 1.00

What is difference between normal typecasting and using “AS” keyword

Using as will fail gracefully if the object is the wrong type, and the resulting value will be null, where a normal cast would throw an InvalidCastException:

object x = new object();
string y = x as string; // y == null
string z = (string)x; // InvalidCastException

What is the difference between object as type and ((type)object) ?


var myString = myObject as string;

It only checks the runtime type of myobject. If its string, only then it cast as string, else simply returns null.

var myString = (string)myObject;

This also looks for implicit conversion to string from the source type. If neither the runtime type is string, nor there is implicit conversion, then it throws exception.

Read Item 3: Prefer the is or as Operators to Casts from Effective C# by Bill Wagner.

Different Cast Types in C#

A cast can do three things:

  • Perform a user-defined conversion
  • Perform an unboxing conversion
  • Perform a reference conversion

An as operation is almost always a reference conversion, the only exception being unboxing to a nullable type:

object x = "hello";
int? y = x as int?; // y is null afterwards

Then there's the behaviour with conversions which fail at execution time. So the differences are:

  • Casts performing reference conversions or unboxing will throw InvalidCastException on failure; as will result in the null value of the target type instead
  • Casts can perform user-defined conversions; as can't
  • Casts can unbox to non-nullable value types; as can only be used for unboxing if the target type is a nullable value type

What is the difference between TypeVar and NewType?

The two concepts aren't related any more than any other type-related concepts.

In short, a TypeVar is a variable you can use in type signatures so you can refer to the same unspecified type more than once, while a NewType is used to tell the type checker that some values should be treated as their own type.

Type Variables

To simplify, type variables let you refer to the same type more than once without specifying exactly which type it is.

In a definition, a single type variable always takes the same value.

# (This code will type check, but it won't run.)
from typing import TypeVar, Generic, List, Tuple

# Two type variables, named T and R
T = TypeVar('T')
R = TypeVar('R')

# Put in a list of Ts and get out one T
def get_one(x: List[T]) -> T: ...

# Put in a T and an R, get back an R and a T
def swap(x: T, y: R) -> Tuple[R, T]:
return y, x

# A simple generic class that holds a value of type T
class ValueHolder(Generic[T]):
def __init__(self, value: T):
self.value = value
def get(self) -> T:
return self.value

x: ValueHolder[int] = ValueHolder(123)
y: ValueHolder[str] = ValueHolder('abc')

Without type variables, there wouldn't be a good way to declare the type of get_one or ValueHolder.get.

There are a few other options on TypeVar. You can restrict the possible values by passing in more types (e.g. TypeVar(name, int, str)), or you can give an upper bound so every value of the type variable must be a subtype of that type (e.g. TypeVar(name, bound=int)).

Additionally, you can decide whether a type variable is covariant, contravariant, or neither when you declare it. This essentially decides when subclasses or superclasses can be used in place of a generic type. PEP 484 describes these concepts in more detail, and refers to additional resources.

NewType

A NewType is for when you want to declare a distinct type without actually doing the work of creating a new type or worry about the overhead of creating new class instances.

In the type checker, NewType('Name', int) creates a subclass of int named "Name."

At runtime, NewType('Name', int) is not a class at all; it is actually the identity function, so x is NewType('Name', int)(x) is always true.

from typing import NewType

UserId = NewType('UserId', int)

def get_user(x: UserId): ...

get_user(UserId(123456)) # this is fine
get_user(123456) # that's an int, not a UserId

UserId(123456) + 123456 # fine, because UserId is a subclass of int

To the type checker, UserId looks something like this:

class UserId(int): pass

But at runtime, UserId is basically just this:

def UserId(x): return x

There's almost nothing more than that to a NewType at runtime. As of Python 3.8.1, its implementation is almost exactly as follows:

def NewType(name, type_):
def identity(x):
return x
identity.__name__ = name
return identity

difference between in-front type conversion and as conversion

Per http://msdn.microsoft.com/en-us/library/cscsdfbt%28v=vs.71%29.aspx (emphasis mine):

The as operator is like a cast except that it yields null on
conversion failure instead of raising an exception
. More formally, an
expression of the form:

expression as type

is equivalent to:

expression is type ? (type)expression : (type)null

except that expression is evaluated only once.

C# difference between casting and as?

as will never throw a InvalidCastException. Instead, it returns null if the cast fails (which would give you a NullReferenceException if obj in your example were not a string).



Related Topics



Leave a reply



Submit