Posted By: ilya | Mar 27th, 2007 @ 7:39 AM
page 1 of 1
Comments: 23 | Views: 5625
Not sure if anyone ever tried but I am currently working on a piece
of functionality in my application and what I want to try to
do is perform different set of logic if the type
that I am working with can figure out what type it was casted into.
For example:

1) I have a User type and it has ID and Username properties.
2) I have a Person type inheriting from User but it also has it's own
    ID property and Firstname. The ID property is being initialized
    with a new tag.

What I want to be able to do is when I create my Person class
and I try to access it's ID property I would get the value that was
assiged to it. But when the object get's casted into a User type
I want to be able to get the value that is assiged to the ID property
of the User type. But the trick is that I want to be able to figure this
logic out from inside the User type.

The problem is that if I say inside the User type this.GetType() and
the object that i am dealing with is a Person it will always tell me
that it is a Person type.

Any thoughts?

Thanks in advance.
I don't think you can do this from within the type. But you can do this:

class User
{
   private int _id;

   public int Id
   {
      get { return _id; }
      set { _id = value; }
   }
}

class Person : User
{
   private int _id;

   public new int Id
   {
      get { return _id; }
      set { _id = value; }
   }
}

Then if you do this:
Person p = GetPersonFromSomewhere();
Console.WriteLine(p.Id);
Console.WriteLine(((User)p).Id);

The first one will access Person.Id, while the second accesses User.Id.
Sven,

I know that you can do it by simply casting, but what I am trying to do is exactly what you are saying that you might not be able to do
and that is by doing this from within the User type.
In my application I actually store the properties
inside a collection that hold the property name and
the property value.
What I want to be able to do is to figure out based on what
casted type i am dealing with, then I should read the appropriate
property collection.
So you want to base class 'user' to do the base interaction, but want it to take inheritance in to context?

Surely you can just use this.GetType() (Me.GetType()), within a method in the User class to establish what the real instance is?
stevo_ wrote:
So you want to base class 'user' to do the base interaction, but want it to take inheritance in to context?

Surely you can just use this.GetType() (Me.GetType()), within a method in the User class to establish what the real instance is?


I don't want to figure out what the real instance is.
What I do want to do is to figure out the type that the
current instance of the object is being used as.
For example if the Person object is inheriting from User
and then the developer casts that person object
into a User type, I want to know that the current type
that that developer is working with is the User type so I
can give them the correct properties and perform specific
logic.
Ok so, you want to know what the developer cast it as, for example:

Dim p as Animal = New Dog()

You would want dog (or its base classes) to know that its cast as an animal?
ilya wrote:

stevo_ wrote: So you want to base class 'user' to do the base interaction, but want it to take inheritance in to context?

Surely you can just use this.GetType() (Me.GetType()), within a method in the User class to establish what the real instance is?


I don't want to figure out what the real instance is.
What I do want to do is to figure out the type that the
current instance of the object is being used as.
For example if the Person object is inheriting from User
and then the developer casts that person object
into a User type, I want to know that the current type
that that developer is working with is the User type so I
can give them the correct properties and perform specific
logic.

There's no built-in support for this. You might be able to use some kind of trick using the shadowed member approach, something like this:

class User
{
   public int Id
   {
      get { return GetPropertyValue("id", typeof(User)); }
   }

   protected virtual void GetPropertyValue(string property, Type type)
   {
      // Stuff
   }
}

class Person : User
{
   public new int Id
   {
      get { return GetPropertyValue("id", typeof(Person)); }
   }

   protected override void GetPropertyValue(string property, Type type)
   {
      // Stuff
   }
}


This is ugly though. Also, what you're trying to do feels wrong to me somehow. Perhaps you need to reconsider your design.
stevo_ wrote:
Ok so, you want to know what the developer cast it as, for example:

Dim p as Animal = New Dog()

You would want dog (or its base classes) to know that its cast as an animal?


Correct,

This way if someone for example does serialization on the object.
I can ask the object what type is the dev dealing with right now
and then only serialize the data relevant to that type.
You mean something like this? (Untested, BTW)

class Animal { ... }

class Canine : Animal { ... }

class Dog : Canine { ... }

void Test()
{
   Dog dog = new Dog();
   ProcessAnimal(dog);

   Canine canine = dog as Canine;
   ProcessAnimal(canine);

   Animal animal = dog as Animal;
   ProcessAnimal(animal);
}


void ProcessAnimal(Animal animal)
{
   if (animal is Animal)
   { ... }
   else if (animal is Canine)
   { ... }
   else if (animal is Dog)
   { ... }
}
Minh wrote:
You mean something like this? (Untested, BTW)

Doesn't work. The is operator will check the object's real instantiated type, not the type of the variable which the OP wants.

I still think this is something you shouldn't need with proper design.

Hope this helps.
Basically what I wanted to be able to do is to have
to display p.Id being different from user.Id
based on their type when the developer casted
the object.

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace ConsoleApplication1
{
   class Program
   {
      static void Main(string[] args)
      {
         Person p = new Person();
         p.ID = 1;
         User user = p as User;
         user.ID = 2;
         Console.WriteLine("PersonID: " + p.ID);
         Console.WriteLine("UserID: " + user.ID);
         Console.ReadLine();
      }
   }
   public class BaseObject
   {
      int _id;
      Hashtable _properties;
      public BaseObject()
      {
         _properties = new Hashtable();
         _properties.Add("User", new Hashtable());
         _properties.Add("Person", new Hashtable());
      }
      public object GetValue(string propName)
      {
         Type cType = this.GetType();
         if (_properties.ContainsKey(cType.Name))
         {
            Hashtable props = _properties[cType.Name] as HashTable;
            if (props.ContainsKey(propName))
            {
               return props[propName];
            }
         }
         return null;
      }
      public void SetValue(string propName, object value)
      {
         Type cType = this.GetType();
         if (!_properties.ContainsKey(cType.Name))
         {
            _properties.Add(cType.Name, new Hashtable());
         }
         Hashtable props = _properties[cType.Name] as Hashtable;
         if (!props.ContainsKey(propName))
         {
            props.Add(propName, value);
         }
         else
         {
            props[propName] = value;
         }
      }
      public int ID
      {
         get 
         { 
            object result = GetValue("Id");return null == result ? -1 : int.Parse(result.ToString());
         }
         set { SetValue("Id", value); 
      }
   }
   public class User: BaseObject
   {
      string _username;
      public string Username
      {
         get { return _username; }
         set { _username = value; }
      }
    }
   public class Person : User
   {
      string _firstname;
      public string Firstname
      {
         get { return _firstname; }
         set { _firstname = value; }
      }
   }
}

Sven Groot wrote:

Minh wrote: You mean something like this? (Untested, BTW)

Doesn't work. The is operator will check the object's real instantiated type, not the type of the variable which the OP wants.

I still think this is something you shouldn't need with proper design.


It's always easy to say that you shouldn't need this with proper design instead here a possible way of doing it.

Just because no one has done it and/or some one has though about implementing logic this way, that it's means it's a bad design.

But thanks for your opinion anyway.
ilya wrote:


Hope this helps.
Basically what I wanted to be able to do is to have
to display p.Id being different from user.Id
based on their type when the developer casted
the object.


That's what the code I first posted does. How is what you want different?

Also, the code for the ID property is horrible. You're storing an int in the hashtable, and to get it back you convert it to a string then parse it back to an int. That's the kind of code that ends up on worsethanfailure.com. Tongue Out You should just cast it to int.
Sven Groot wrote:

ilya wrote: 

Hope this helps.
Basically what I wanted to be able to do is to have
to display p.Id being different from user.Id
based on their type when the developer casted
the object.


That's what the code I first posted does. How is what you want different?



Try running the code that I have put together, it does not work the way that I want it to.
In the main function it should return PersonId: 1 and UserId: 2.
In GetValue function it always sees the Person object as a person object and not the casted type.
I am curious if there is a way to find out if the dev casted an object into a different type.
I basically want to do what you have done inside the BaseObject instead of having to pass the actual type to the function.
This way no matter how many different types I might have, I don't have to implement that logic every place.
ilya wrote:

Sven Groot wrote: 
ilya wrote: 

Hope this helps.
Basically what I wanted to be able to do is to have
to display p.Id being different from user.Id
based on their type when the developer casted
the object.


That's what the code I first posted does. How is what you want different?



Try running the code that I have put together, it does not work the way that I want it to.

I know it doesn't, but I already posted the only way there is to get around that, by hiding the base class properties. You cannot have the BaseObject be solely responsible for this. It defeats the whole idea behind polymorphism.
Sven Groot wrote:

Minh wrote:You mean something like this? (Untested, BTW)

Doesn't work. The is operator will check the object's real instantiated type, not the type of the variable which the OP wants.

I just typed in the example, and "is" doesn't return true for just the instantiated type.

It returns true for the entire class hierarchy.

ie,

Dog dog = new Dog();

dog is Dog == true
dog is Canine == true
dog is Animal == true

...

So, I'll revise my code... this seems to be working...

class Animal { ... }

class Canine : Animal { ... }

class Dog : Canine { ... }

void Test()
{
   Dog dog = new Dog();
   ProcessAnimal(dog);

   Canine canine = dog as Canine;
   ProcessAnimal(canine);

   Animal animal = dog as Animal;
   ProcessAnimal(animal);
}


void ProcessAnimal(Animal animal)
{
   // Do Animal-specific stuff
}

void ProcessAnimal(Canine canine)
{
   // Do Canine-specific stuff
}

void ProcessAnimal(Dog dog)
{
   // Do Dog-specific stuff
}

Looking at what you want to do, I agree w/ Sven. A different approach is in order.
I have to agree with Sven and Minh, I don't think what you are trying to do really makes sense. I have a feeling you are unnecessarily overloading Id and that you'd be better splitting it into two separate properties (one which exists in the base class and the other only in the derived class).
AndyC wrote:
I have to agree with Sven and Minh, I don't think what you are trying to do really makes sense. I have a feeling you are unnecessarily overloading Id and that you'd be better splitting it into two separate properties (one which exists in the base class and the other only in the derived class).


Maybe the example that I am giving is not the best one.
One of the reasons that I need to have the ability to do something
like this is because of how my data layer works.
What I am trying to do is to do an inheritence on the programming
side and some sort of inheritence on the database level.
The kind of scenario that I am proposing here is what would
help me in figuring out what things I would have to call on the
data layer to perform specific functions.

Thanks for everyone's input and I guess I will have to investigate
this on my own.
Yes.. seems you should investigate it on your own, or preface your post with enough background on what you are really trying to do as to justify your approach. I think it is normal for someone to see what appears to be bad practice and step back from it, if you have a good justification and can explain that I'm sure others would be willing to investigate that problem deeper.
ilya wrote:


The kind of scenario that I am proposing here is what would
help me in figuring out what things I would have to call on the
data layer to perform specific functions.



The trouble is that what you are proposing would make the base class have dependencies on derived classes. That sort of circular dependency is really bad from an design point of view.
This works:
static void Main(string[] args)
{
    Person p = new Person();
    User u = p as User;

    p.Id = 100;
    Console.WriteLine(p.Id);
    Console.WriteLine(u.Id);

    u.Id = 5;
    Console.WriteLine(p.Id);
    Console.WriteLine(u.Id);

    Console.ReadLine();
}

class Person : User
{
    private int id;
    private string firstName;

    public int Id
    {
        get { return id; }
        set { id = value; }
    }

    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; }
    }
}

class User
{
    private int id;
    private string userName;

    public int Id
    {
        get { return id; }
        set { id = value; }
    }

    public string UserName