tags:

views:

348

answers:

3

Is there a way to cast an instance of a class using a Type variable rather then an explicitly provided type?

For example in my method below "this" is a derived type of "Node". I want the method to repeatedly try to get a value from GetNodeIntrinsicProperty() after which if it get's a null value it should cast itself as it's base type and try again.

Basically, I want to call every implementation of GetNodeIntrinsicProperty() until I get a value.

        public string GetIntrinsicProperty(String propertyKey)
    {
        //sets the original type value
        Type currType = this.GetType();

        Node thisNode = this;
        String propertyValue;

        while (currType is Node)
        {
            //casts thisNode as CurrType
            thisNode = thisNode as currType;

            /*The live above gives me the following error
             * 
             * Error    20 The type or namespace name 'currType' could not be found 
            (are you missing a using directive or an assembly reference?)   */



            //trys to get the property with the current cast
            //GetNodeIntrinsicProperty() is defined seperately in each type
            propertyValue = thisNode.GetNodeIntrinsicProperty(propertyKey);

            if (propertyValue != null)
            {
                return propertyValue;
            }

            //sets CurrType to its base type
            currType = currType.BaseType;
        }

        return null;
    }
A: 

I didn't fully understand what you're trying to do, but you can convert an object to a specific type using Convert.ChangeType(yourObject, yourType). It returns an object of type object so you still have to cast it manually. I don't know if that helps.

sker
Ok say I have the follow inheritance Base->Derived->ConcreteConcrete instance = new Concrete();Base castInstance;castInstance = (Base)Convert.ChangeType(derivedInstance,Derived);String result = castInstance.MyMethod();What version of MyMethod() will be run and return a result?
Eric Anastas
A: 

Ok, so first the answer to your question.

I'm assuming you have some structure like this:

    public class Node
    {
        public string GetIntrinsicProperty(String propertyKey)
        {
            //sets the original type value
            Type currType = this.GetType();

            Node thisNode = this;
            String propertyValue;

            while (currType.IsSubclassOf(typeof(Node)))
            {
                MethodInfo mi = currType.GetMethod("GetIntrinsicProperty",BindingFlags.Instance | BindingFlags.Public,null,new Type[] {typeof(string)},null);
                if (mi.DeclaringType != typeof(Node))
                {
                    propertyValue = (string)mi.Invoke(this, new object[] { propertyKey });

                    if (propertyValue != null)
                    {
                        return propertyValue;
                    }
                }
                //sets CurrType to its base type
                currType = currType.BaseType;
            }
            return null;
        }
    }

    public class OtherNode : Node
    {
        new public string GetIntrinsicProperty(string propertyKey)
        {
            return "OtherNode says Hi!";
        }
    }

    public class TestNode : Node
    {
    }

The implementation of GetIntrinsicProperty above will do what you're asking, but I would suggest that it's wrong.

You're forcing a child class to exactly replicate your signature and a developer to understand what you want. This is what virtual methods are for. If I'm understanding you correctly the proper way to do what you want is this:

    public class Node
    {
        public virtual string GetIntrinsicProperty(String propertyKey)
        {
            switch(propertyKey)
            {
                case "NodeUnderstoodProp":
                    return "I know! Call on me!";
                default:
                    return null;
            }
        }
    }

    public class OtherNode : Node
    {
        public override string GetIntrinsicProperty(string propertyKey)
        {
            switch (propertyKey)
            {
                case "OtherUnderstoodProp":
                    return "I'm the OtherNode, and I know better, call on me!";
                default:
                    return base.GetIntrinsicProperty(propertyKey);
            }
        }
    }

    public class TestNode : Node
    {
    }


    static void Main(string[] args)
    {
        Node node = new OtherNode();
        var prop1 = node.GetIntrinsicProperty("NodeUnderstoodProp");
        var prop2 = node.GetIntrinsicProperty("OtherUnderstoodProp");
        var prop3 = node.GetIntrinsicProperty("PropTooHard!");

        node = new TestNode();
        prop1 = node.GetIntrinsicProperty("NodeUnderstoodProp");
        prop2 = node.GetIntrinsicProperty("OtherUnderstoodProp");
        prop3 = node.GetIntrinsicProperty("PropTooHard!");
    }

The idea of virtual methods is that the type of your variable doesn't determine which implementation is called, but rather the run time type of the object determines it.

As far as I can tell, the situation you're describing is one where you are trying do your own dispatch to the implementation of a method on the runtime type of the object. Pretty much the definition of a virtual method.

If I didn't get the question right, please clarify. :)

Darren Clark
Basically I want the user to be able to add their own properties with unique keys, but then I want a common interface that can access both the user custom properties and intrinsic class properties. Every node has a "Node.Name" property, which I want to return when the user provided the key "name".
Eric Anastas
Yes your second example was exactly what I was trying to do. Yet I was trying to figure out a way where a future developer does not need to know that he/she should always call Base.GetIntrinsicProperty() as a default.
Eric Anastas
There would end up being a base.GetIntrinsicProperty() call in every version of GetIntrinsicProperty(), which seemed inefficient and repetitive.
Eric Anastas
I should also clarify, as this confused others as well, trying to answer my question. GetNodeIntrinsicProperty() is already virtual and defined separately in each version of node. The intent of GetIntrinsicProperty() was to call every version of GetNodeIntrinsicProperty() until it got a result.
Eric Anastas
+1  A: 

Alright I took a step back and realized that what I'm really doing is trying to create a method that will return the value of a public property by passing the the property name. Rather then manually creating a relationship between a property in my class and a string that coincidentally has the same name I've figured that it's better to do that automatically.

So here's what I'm doing now, and it seems to work. In addition, I don't have to worry about two classes trying to define duplicate property keys because a derived class already can't have a duplicate property name to one in its base class unless there is an explicit abstract/override relationship.

    public HashSet<string> GetIntrinsicPropertyKeys()
    {
        Type t = this.GetType();
        PropertyInfo[] properties = t.GetProperties();
        HashSet<string> keys = new HashSet<string>();

        foreach (PropertyInfo pNfo in properties)
        {
            keys.Add(pNfo.Name);
        }

        return keys;
    }


    public string GetIntrinsicProperty(string propertyKey)
    {
        HashSet<string> allowableKeys = this.GetIntrinsicPropertyKeys();
        String returnValue = null;

        if (allowableKeys.Contains(propertyKey))
        {
            Type t = this.GetType();
            PropertyInfo prop = t.GetProperty(propertyKey);

            returnValue = (string)prop.GetValue(this, null);
        }
        return returnValue;
    }
Eric Anastas