我可以通过Type变量而不是显式类型来转换类的实例吗?

时间:2022-05-02 22:50:09

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

有没有办法使用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.

例如,在我的方法中,“this”是派生类型的“Node”。我希望该方法重复尝试从GetNodeIntrinsicProperty()获取一个值,之后如果它得到一个空值,它应该将自己转换为它的基类型并再试一次。

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

基本上,我想调用GetNodeIntrinsicProperty()的每个实现,直到我得到一个值。

        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;
    }

3 个解决方案

#1


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.

上面的GetIntrinsicProperty的实现将做你所要求的,但我认为这是错误的。

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. :)

如果我没有得到正确的问题,请澄清。 :)

#2


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;
    }

#3


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.

我没有完全理解你要做的是什么,但你可以使用Convert.ChangeType(yourObject,yourType)将对象转换为特定类型。它返回一个object类型的对象,因此您仍然需要手动转换它。我不知道这是否有帮助。

#1


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.

上面的GetIntrinsicProperty的实现将做你所要求的,但我认为这是错误的。

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. :)

如果我没有得到正确的问题,请澄清。 :)

#2


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;
    }

#3


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.

我没有完全理解你要做的是什么,但你可以使用Convert.ChangeType(yourObject,yourType)将对象转换为特定类型。它返回一个object类型的对象,因此您仍然需要手动转换它。我不知道这是否有帮助。