From the docs:
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.
So why wouldn't you choose to either do it one way or the other. Why have two systems of casting?
They aren't two system of casting. The two have similar actions but very different meanings. An "as" means "I think this object might actually be of this other type; give me null if it isn't." A cast means one of two things:
I know for sure that this object actually is of this other type. Make it so, and if I'm wrong, crash the program.
I know for sure that this object is not of this other type, but that there is a well-known way of converting the value of the current type to the desired type. (For example, casting int to short.) Make it so, and if the conversion doesn't actually work, crash the program.
See my article on the subject for more details.
https://ericlippert.com/2009/10/08/whats-the-difference-between-as-and-cast-operators/
Efficiency and Performance
Part of performing a cast is some integrated type-checking; so prefixing the actual cast with an explicit type-check is redundant (the type-check occurs twice). Using the as keyword ensures only one type-check will be performed. You might think "but it has to do a null check instead of a second type-check", but null-checking is very efficient and performant compared to type-checking.
if (x is SomeType )
{
SomeType y = (SomeType )x;
// Do something
}
makes 2x checks, whereas
SomeType y = x as SomeType;
if (y != null)
{
// Do something
}
makes 1x -- the null check is very cheap compared to a type-check.
Because sometimes you want things to fail if you can't cast like you expect, and other times you don't care and just want to discard a given object if it can't cast.
It's basically a faster version of a regular cast wrapped in a try block; but As is far more readable and also saves typing.
It allows fast checks without try/cast overhead, which may be needed in some cases to handle message based inheritance trees.
I use it quite a lot (get in a message, react to specific subtypes). Try/cast wouuld be significantly slower (many try/catch frames on every message going through) - and we talk of handling 200.000 messages per second here.
Let me give you real world scenarios of where you would use both.
public class Foo
{
private int m_Member;
public override bool Equals(object obj)
{
// We use 'as' because we are not certain of the type.
var that = obj as Foo;
if (that != null)
{
return this.m_Member == that.m_Member;
}
return false;
}
}
And...
public class Program
{
public static void Main()
{
var form = new Form();
form.Load += Form_Load;
Application.Run(form);
}
private static void Form_Load(object sender, EventArgs args)
{
// We use an explicit cast here because we are certain of the type
// and we want an exception to be thrown if someone attempts to use
// this method in context where sender is not a Form.
var form = (Form)sender;
}
}
I generally choose one or the other based on the semantics of the code.
For example, if you have an object that you know that it must be an string then use (string) because this expresses that the person writing the code is sure that the object is a string and if it's not than we already have bigger problems than the runtime cast exception that will be thrown.
Use as if you are not sure that the object is of a specific type but want to have logic for when it is. You could use the is operator followed by a cast, but the as operator is more efficient.
Maybe examples will help:
// Regular casting
Class1 x = new Class1();
Class2 y = (Class2)x; // Throws exception if x doesn't implement or derive from Class2
// Casting with as
Class2 y = x as Class2; // Sets y to null if it can't be casted. Does not work with int to short, for example.
if (y != null)
{
// We can use y
}
// Casting but checking before.
// Only works when boxing/unboxing or casting to base classes/interfaces
if (x is Class2)
{
y = (Class2)x; // Won't fail since we already checked it
// Use y
}
// Casting with try/catch
// Works with int to short, for example. Same as "as"
try
{
y = (Class2)x;
// Use y
}
catch (InvalidCastException ex)
{
// Failed cast
}
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.
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)
I have a type ConfigValue that exposes a dynamic interface via an implementation of IDynamicMetaObjectProvider and custom DynamicMetaObject instance.
An instance of this type can be seen, of course, as it's native type - analogous to an XML Element - but it can also be seen as an instance of any other object type, according to the contents of the XML and what kind of object it builds (it's a proprietary IOC built by little old me).
So
<value>10</value>
Can be seen as a ConfigValue but also potentially a string, short, double etc. Conversion is achieved by implicit or explicit cast, as specified by the calling language. The XML gets more complicated because you can fire constructors, methods, property gets etc.
To achieve this, of course, I have overriden the BindConvert member of the DynamicMetaObject type - and if the conversion is unsupported by the ConfigValue object at runtime, then a runtime error occurs (which is fine).
I've just started writing a piece of code where it would be great if I could do a safe cast to the target type, but if that doesn't work fallback to some other logic - analogous to:
public DesiredType Foo(dynamic d)
{
DesiredType dt = d as dt;
if(dt != null)
return dt;
//TODO: Fallback logic to build dt from d
}
But, C# at least (and probably all dynamic-aware languages I'm sure) doesn't emit any dynamic binding for the 'as' or 'is' operations; presumably because DynamicMetaObject doesn't have a method for such a test. Thus the type test is just performed on the static type information which, in this case, always fails.
As a result I'm having to rely on the rather ugly:
public DesiredType Foo(dynamic d)
{
try
{
return (DesiredType)d;
}
catch(Exception)
{
//TODO: fallback logic
}
}
Any ideas how I can avoid the try/catch/gulp pattern here!? The best I can think of is something on top of DynamicMetaObject; but then that has to be queried for first, before then being queried again for the type test; which is just going to explode the code up even further!
I don't think it is possible.
Take for example, this code:
class Program
{
static void Main(string[] args)
{
dynamic d = new object();
var x = (Program)d;
Console.WriteLine(x);
var y = d as Program;
Console.WriteLine(y);
var z = d is Program;
Console.WriteLine(z);
}
}
If we decompile it using Reflector we see that the only reason that the cast is able to be intercepted by the dynamic type is that the C# compiler does a lot of extra work in order to support it:
class Program
{
private static void Main(string[] args)
{
object d = new object();
if (<Main>o__SiteContainer0.<>p__Site1 == null)
{
<Main>o__SiteContainer0.<>p__Site1 = CallSite<Func<CallSite, object, Program>>.Create(Binder.Convert(CSharpBinderFlags.ConvertExplicit, typeof(Program), typeof(Program)));
}
Console.WriteLine(<Main>o__SiteContainer0.<>p__Site1.Target(<Main>o__SiteContainer0.<>p__Site1, d));
Program y = d as Program;
Console.WriteLine(y);
bool z = d is Program;
Console.WriteLine(z);
}
}
In contrast, the as and is calls are simply compiled down to IL instructions, with no added magic from the C# compiler.
This fits in with the normal casting operators as well; using as rather than a cast will not perform any conversion casts, so will never change the type of the underlying object.
is and as are runtime tests that only work on inheritance, thus they don't need to dynamically bind because they are already dynamic. Even without the dynamic keyword you could never use is or as to test for implict or explicit conversions, and they never would work on value types like short and double either.
So your answer is that there is no need to fake it, they work exactly the same for dynamic types as static types. Your try catch is probably the best way to test the conversion, catching binding errors is what the DLR is already doing in the background for a lot of it's fallback cases. You can see for yourself in the debugger if you stop on first chance exceptions.
The best way to improve your try catch would be to specify the exact exception.
catch(RuntimeBinderException)
{
//TODO: fallback logic
}
In lieu of the fact that it's not supported, I've written this very basic static method to simplify the operation of testing the conversion.
public static class DynamicHelper
{
public static TResult As<TResult>(dynamic obj) where TResult : class
{
if (obj == null)
return null;
try
{
return (TResult)obj;
}
catch (Exception)
{
return null;
}
}
}
It's top-drawer code that ;)
I'm currently doing a project in C# working with windows forms. During the course of it, I did the following
void HideButtons(object sender, EventArgs e)
{
Button hider = ((Button)sender);
foreach(Button tohide in hider.Parent.Controls)
tohide.Hide();
hider.Show();
hider.Text = "UnHide";
hider.Click -= new EventHandler(HideButtons);
hider.Click += new EventHandler(ShowButtons);
}
The purpose of this code is to have a button which hides all the other buttons in the container it's in except itself, and then turn into an Unhide button which does the same thing in reverse.
Now, that's all well and good, except, as I compile this, I realize to myself I've hit a problem. hider is its unique object, being the return from ((Button)sender). It's not necessarily the reference to sender, and this code will probably do nothing.
But low and behold, it works exactly like I wanted it to and initially thought it would. Which got me to wondering, does a cast always return a reference to the original object? If not, how do I guarantee that (button)sender = sender?
I know that's not the case for doubles/ints, as
public static int Main()
{
int a;
double b;
b = 10.5;
a = (int)b;
a++;
return 0;
}
ends up with a being 11, and b being 10.5 But that may be due to doubles/ints being structs. This behavior worries me, and it'd be nice to know that it will always return a reference so I can put my worrysome mind to rest.
For reference types. if the cast is just up or down the inheritance hierarchy, then yes. This is a reference conversion. From the C# 3.0 language spec, section 6.2.4:
Reference conversions, implicit or
explicit, never change the referential
identity of the object being
converted. In other words, while a
reference conversion may change the
type of the reference, it never
changes the type or value of the
object being referred to.
This is the case you're using in your WinForms code.
However, in other (still reference type) cases it may invoke a user-defined conversion. For example:
using System;
class Foo
{
}
class Bar
{
public static explicit operator Bar(Foo f)
{
return new Bar();
}
}
class Test
{
static void Main()
{
Foo f = new Foo();
Bar b = (Bar) f;
Console.WriteLine(object.ReferenceEquals(f, b)); // Prints False
}
}
User-defined conversions like this are relatively rare.
For value types, there are boxing and unboxing conversions, along with other conversions (e.g. between int and double).
For reference types casted through the inheritance hierarchy, it'll always reference the same instance. However, for value types, casts might involve boxing and unboxing which will copy stuff. Other than that, casts are not just in the inheritance hierarchy. You can declare your own cast operator which has the characteristics of a method. It can return whatever object it likes.
I have a method which is taking in a parameter that is a Interface object
like this
private void SomeMethod(InterfaceA IUA)
Inside the method I have a statement like this
ClassD someVar = (ClassD)(((ClassC)((ClassB)IUA)).D);
everything if fine and dandy. However, in certain cases the object IUA might be instance of ClassZ rather than ClassB. So in that case the above line errors out. Is there a way to find out, before doing above statement, that which class does the object really belong to? If i know that before hand then I can have an If statement and do the following
ClassZ someVar = (ClassD)(((ClassC)((ClassZ)IUA)).Z);
I come from java background...In java i know we have getClass() ...what would be the equivalent in .net?
You really shouldn't be writing code like this without good reason.
That said: you can use is
if (a is ClassB)
{
ClassB b = (ClassB)a;
}
else if (a is ClassZ)
{
ClassZ z = (ClassZ)a;
}
...or as:
ClassB b = a as ClassB;
if (b != null)
{
// ...
}
Well, for starters, you're not really supposed to downcast from interface to a class, unless you have a really good reason to do so. If you need ClassD functionality, then your method should receive ClassD, not InterfaceA.
Another thing that confuses me is the multiple downcasting. I use both Java and C# and I've never seen the need to do a multiple cast like that.
Finally, you could use operator "is" to find out whether certain type inherits from a certain class or implements a certain interface, as in
if (IUA is ClassD)
{
// do something
}
You can do
if (someVar is ClassZ)
Which returns TRUE if someVar is-a ClassZ,
or
someVar.GetType ()
to get the actual class
How about
if(IUA is ClassB)
someVar = (IUA as ClassB).B;
elseif (IUA is ClassZ)
someVar = (IUA as ClassZ).Z;
That should work, though you get the mandatory scolding that this is a rather poor architecture.
What is the point of passing the interface if your just going to cast it away? You might want to re-evaluate the design as code like this defeats the purpose of polymorphism.
Also you should not use 'is' to test the type. Since you are going to cast the object anyway you should use 'as' and test for null.
Okay, a few different options here:
The equivalent for Java's getClass() is GetType(); you can use typeof(...) to retrieve the Type object for a type you know at compile-time. This isn't the best way of testing things though, unless you're interested in exact equality.
The equivalent of Java's instanceof operator is the is operator in C#:
if (x is SomeType) ...
This can be used with boxed values to check for value types, too:
if (x is int) ...
A related operator is the as operator, which doesn't return true or false, but a reference of the type specified. The type has to be a nullable type (reference or nullable value type) and the result is the original value but strongly typed as the target type if the value is a reference of an appropriate type, or null otherwise. For instance:
object x = "hello";
string y = x as string; // y = "hello" now
Stream z = x as Stream; // z = null now
In the case where you want to check whether or not a reference is of a particular type, and then use it as a reference of that type, a common pattern is:
object x = GetObjectFromSomewhere();
string y = x as string;
if (y != null)
{
Console.WriteLine(y.Length); // Whatever
}
This is more efficient than the equivalent to what's required in Java:
object x = GetObjectFromSomewhere();
if (x is string)
{
string y = (string) x;
Console.WriteLine(y.Length); // Whatever
}
If it's a bug for the reference to be of the wrong type, just cast - that way you'll get an exception thrown if you've got a bug, which is almost certainly the best course of action at that point.
I don't think it's necessary to cast IUA to ClassB. You're not using any of the ClassB methods as far as I can tell.
You could do something like
If (IUA is ClassB)
//I am class b
However, given that your method is taking an interface, I would question your design if you are looking to get back to the actual concrete type. Can you re-factor to create an interface method that you can use to perform the actions of that method.
From MSDN:
public static void Test (object o)
{
Class1 a;
Class2 b;
if (o is Class1)
{
Console.WriteLine ("o is Class1");
a = (Class1)o;
// do something with a
}
else if (o is Class2)
{
Console.WriteLine ("o is Class2");
b = (Class2)o;
// do something with b
}
else
{
Console.WriteLine ("o is neither Class1 nor Class2.");
}
}
You should use method overloading, this is how it should look:
private void SomeMethod(ClassB obj) {
DoMoreStuff(obj.B);
}
private void SomeMethod(ClassZ obj) {
DoMoreStuff(obj.Z);
}
private void DoMoreStuff(int val) {
// ..
}