views:

158

answers:

3

Hello all,

Again, I really hope this isn't a matter of opinion; I'm trying to know which is the best way to determine the type of an object that belongs to a certain hierarchy in C#. I have two ways to design my application:

1 - Use a property on the base class:

public abstract class Parent 
{
    public abstract TypeOfObject TypeOfObject { get; }
}

public class Child1 : Parent
{
    public override TypeOfObject TypeOfObject { get { return TypeOfObject.Child1 } }

    // ...
}

public class Child2 : Parent
{
    public override TypeOfObject TypeOfObject { get { return TypeOfObject.Child2 } }

    // ...
}

public enum TypeOfObject 
{
    Child1,
    Child2
}

public static void Main()
{
    Parent p = new Child1();

    switch (p.TypeOfObject)
    {
        case TypeOfObject.Child1: _doSomethingWithChild1(p);break;
        case TypeOfObject.Child2: _doSomethingWithChild2(p);break;
    }
}

2 - Use the is operator

public abstract class Parent 
{
    // ...
}

public class Child1 
{
    // ...
}


public class Child2 : Parent
{    
    // ...
}

public enum TypeOfObject 
{
    Child1,
    Child2
}

public static void Main()
{
    Parent p = new Child1();

    if (p is Child1) _doSomethingWithChild1(p);
    if (p is Child2) _doSomethingWithChild2(p);
}

What are the implications of each alternative? I think 2 has a greater performance hit since it relies on metadata, but 1 seems way less elegant. Besides, I learned to do this the 1 way in C++... I'm not sure it's necessary to do so with C#.

EDIT 1:

I've added the override keyword to the code above.

EDIT 2:

I'm sorry, I've probably not made myself clear. I will illustrate it better:

For example, I have a WPF Panel object that has a Children property, which returns me UIElements. I need to know what type a certain element is to act upon it... in my particular case, the user is drawing a graph on the screen, so I need to know how many nodes and how many connections are drawn in order to store then at the database. I can't, unfortunately, use polymorphism for that, right? How will I know if I should add a line to my nodes table or to my connections table?

+3  A: 

the first alternative is not neccessary. if you look at Object (the base for ALL objects in C#) you will find a GetType() member.

In our production code, we frequently use method 2, mainly for "down-casting" that is, casting my a base class to a class that is derived from said base class...

if ( myObject is Type1 ) dosomething();
if ( myObject is Type2 ) dosomethingelse();

we also use the as operator....

Type1 object1 = someotherobject as type1;
if ( object1 != null ) dosomething();

the nice thing about this, is that you won't get exceptions like you would if you tried something like this:

((TypeFoo)object1).bar(); // if object 1 is NOT of TypeFoo you get an exception
Muad'Dib
Did you mean `GetType` instead of `TypeOf`?
Gabe
Polymorphism should make something *different* occur based on whether `myObject` is of type `Type1` versus `Type2` without having to explicitly check. If you're operating on `myObject` and needing to distinguish its concrete type, that means you're inappropriately coupled to it and need to refactor.
FMM
by all means, you should use polymorphism if you can, however, sometime you don't have that option. for example, LINQ gives me an IEnumerable, but if that is *really* a List of something, how can i know that if i don't test it?
Muad'Dib
+10  A: 

You are doing it wrong™. Ever heard of polymorphism (late/dynamic binding to be more precise)? The parent should should have an abstract method like doSomething() to be implemented by the children, whatever was in _doSomethingWithChild1 should be in Child1.doSomething, etc. This is what OO is all - well, not all, but to a large part - about! The C++ FAQ is right claiming that C++ wouldn't be object oriented without virtual. Not only it's easier/less error-prone to add another child (you just define a new subclass and the method, no need to fiddle with switches or ifs) and very likely the fastest way possible (every JIT worth its salt uses polymorphic inline caching), it's also idiomatic and less likely to get you that "WTF" stare ;)

delnan
This is effectively the same thing as a switch statement. If you're "switching" on the runtime type, I agree, You're Doing It Wrong(TM). Look around for refactoring switch statements to polymorphism.
FMM
I've edited the question in order to produce a clearer example. The objects may be polymorphic, but there will be times when I need to know the exact type of them.
Bruno Brant
@Bruno: How exactly does the example not work with polymorphism? If you would otherwise insert things into a database depending on the type, just make the objects (polymorphically) put this information into the db?
delnan
@delnan: Simply because then I would hurt another principle of my application design, separation of concerns. UI objects should know nothing about my database.
Bruno Brant
@Bruno: "All problems in computer science can be solved by another level of indirection (except for the problem of too many layers of indirection)" ^^ E.g. you *could* add yet another layer where each object goes with one of those UI objects, and their concern is to fill the database etc. Although this gets ridiculous after a few times, i.e. in your case I would propably re-label the "Use polymorphism!" advice as "really consider this" (where it usually is "you must do this in 95% of the cases").
delnan
A: 

Your use examples are wrong (as other have said - use polymorphism) but it can be reasonable to ask what type an object is.

I asked a similar question for c++ http://stackoverflow.com/questions/3336859/testing-a-c-class-for-features

Regarding the difference between #1 and #2. Both require metadata. In case 1 you are making it, in case 2 you are using metadata made by the CLR anyway. The CLR is probably better at it than you , and its paying that overhead anyway

As always - if you want to know which is faster the answers is simple - measure it and see. I doubt there is a measurable difference

pm100
"it can be reasonable to ask what type an object is." Please provide an example of when it's actually "reasonable" that doesn't involve Pretty Poor Polymorphism. Sadly, **all** the examples of run-time type identification I've ever seen are all bad polymorphism mistakes. Please clarify with an example.
S.Lott
http://stackoverflow.com/questions/3336859/testing-a-c-class-for-features
pm100
@pm100: How is that not yet another example of bad polymorphism? It looks like something that should have been simple polymorphism. What did I miss?
S.Lott
how do i tell the user that the currently selected object does not support a given method if I cant ask it what interfaces it supports. I am not doing polymorhpism - i am doing mixins
pm100
@S.Lott: although it's not my intention to turn this into a discussion, I'd ask you to look at my example. I have UI objects which are to be added to the database. They shouldn't know about the database itself. Is there a better way to convert then to database objects than having the component that does communicates to the DB ask them their type?
Bruno Brant
@Bruno Brant: None of this indicates anything but a simple piece of code calling out for simple Polymorphism. ORM layers handle this conversion of object to database row without you having to write any code. I'm failing to see how Database persistence has anything to do with your question. Perhaps your question is incomplete and the question needs to include the "I'm writing my own ORM layer" or similar clarification.
S.Lott
@S.Lott: That might be the case. I'm mapping a set of DBML (DLINQ) to a set of entities and I can't use the Entity Framework for that, so I've written the mappings myself. But from what you've written, I'm pretty sure I'm lacking knowledge on how to do this the proper way. I have the is operator in a number of places in two classes in my program, which does similar mappings.
Bruno Brant
@Bruno Brant: "I can't use the Entity Framework for that," That sounds like your **real** question. Why can't you use the Entity Framework? Why can't you use standard, off-the-shelf object mappings?
S.Lott
@S.Lott: Has not been approved by the client yet, and we are already at mid point in the project. The client has worries about newer technologies because evolution and maintainability are handled by external "software factories", which are cheaper but don't have specialized workforce. In fact, we are forced to use Visual Studio 2008 and .Net Framework 3.5 in the project.
Bruno Brant
I've chosen this answer as the correct one mainly because it focus on the problem at hand. I, however, am thankful for S.Lott advice and have upvoted it.
Bruno Brant