Reputation: 3428
I have a method that gets an object
that can be of various types. Depending of the type
of the object
I need to do different actions. My current code is like this:
public void SomeMethod(object obj)
{
int? someId = null;
Class1 class1 = obj as Class1;
Class2 class2 = obj as Class2;
Class3 class3 = obj as Class3;
Class4 class4 = obj as Class4;
if (class1 != null && class1.SomeProperty != null)
{
someId = class1.SomeProperty.Id;
}
else if (class2 != null && class2.AnotherProperty != null)
{
someId = class2.AnotherProperty.AnotherId;
}
...
AnotherMethod(someId);
}
I am not quite satisfied with this code as I do have some unnecessary casts. Which would be the most efficient way to do such an operation? I was thinking about something like:
if (obj.GetType().Equals(typeOf(Class1))
{
someId = ((Class1)obj).SomeProperty.Id;
}
Any suggestions?
Upvotes: 1
Views: 142
Reputation: 229
I would use:
if (obj is Class1 && ((Class1)obj).SomeProperty)
someId = ((Class1)obj).SomeProperty.Id;
Final code would look like this:
if (obj is Class1 && ((Class1)obj).SomeProperty)
someId = ((Class1)obj).SomeProperty.Id;
else if (obj is Class2 && ((Class2)obj).AnotherProperty)
someId = ((Class2)obj).AnotherProperty.Id;
else if (obj is Class3 && ((Class3)obj).OnceAgainAnotherProperty)
...
In every if
and else if
conditions, if the first check obj is X
fails it will not do the second ((X)obj).XProperty
. So at the end of the day, only two casts will be performed, even if your object as the type Class4
.
Upvotes: 0
Reputation: 11549
I think you should first try doing this without casting. You can define an interface and explicitly implement this interface for each Classn
. I assume Classn
classes are not third party and you can modify them.
public interface IIdProvider {
int? Id { get; }
}
public class Class1 : IIdProvider {
int? IIdProvider.Id {
get {
return SomeProperty != null ? SomeProperty.Id : null;
}
}
}
public class Class2 : IIdProvider {
int? IIdProvider.Id {
get {
return AnotherProperty != null ? AnotherProperty.AnotherId : null;
}
}
}
Having this, SomeMethod
does not care where the Id comes from. If you want to add Class5
, Class6
etc you do not have to modify SomeMethod
. Instead each newly added class will take care of the Id
thing itself. Having this, we can do the following.
public void SomeMethod(IIdProvider obj)
{
AnotherMethod(obj.Id);
}
Upvotes: 2
Reputation: 726579
Both alternatives are pretty bad, because they do explicit casts, and dispatch by checking the type manually. This is error-prone, and leads to inevitable maintenance headaches when you expand the list of types that your method needs to handle.
Starting with .NET 4.0, you have a better option - dispatch using dynamic
:
public void SomeMethod(dynamic obj) {
SomeMethodImpl(obj);
}
private void SomeMethodImpl(Class1 obj) {
// Perform actions specific to Class 1
}
private void SomeMethodImpl(Class2 obj) {
// Perform actions specific to Class 2
}
private void SomeMethodImpl(Class3 obj) {
// Perform actions specific to Class 3
}
private void SomeMethodImpl(Class4 obj) {
// Perform actions specific to Class 4
}
private void SomeMethodImpl(object obj) {
// Catch all
}
Now you can place the code specific to a class in its own overload of SomeMethodImpl
, without running a chain of conditional statements. Expanding your method to handle additional types is simple as well - all you need to do is adding another overload.
Note: I assume that the signature of SomeMethod
must remain the same - in other words, you cannot address this problem simply by overloading SomeMethod
.
Upvotes: 5
Reputation: 7903
Polymorphism??
public void SomeMethod(Class1 class1)
{
AnotherMethod(class1.SomeProperty.Id);
}
public void SomeMethod(Class2 class2)
{
AnotherMethod(class2.NewProperty.Id);
}
.
.
.
Instead why not call AnotherMethod(class1.SomeProperty.Id);
,.. AnotherMethod(class2.NewProperty.Id)
directly if that is all you wanted to do...
If you really want to check if the object is of certain type use if(obj is Class1)
instead of casting it
Upvotes: 2
Reputation: 7504
In this particular case (get single value of a variable), it could be more efficient to use switch-like approach, something like:
public int? GetSomeId(object obj) {
Class1 class1 = obj as Class1;
if (class1 != null)
{
return class1.SomeProperty != null ? class1.SomeProperty.Id : (int?)null;
}
Class2 class2 = obj as Class2;
if (class2 != null)
{
return class2.AnotherProperty != null ? class2.AnotherProperty.AnotherId : (int?)null;
}
....
return null;
}
Upvotes: 1
Reputation: 698
as
keyword exists for programmer conciseness. It gets translated to
Class1 class1 = obj is Class1 ? (Class1)obj : null;
I thinks go with as
as it looks more readable and also does not affect performance.
Upvotes: 0