【问题标题】:Get Property of generic type object without knowing the generic type在不知道泛型类型的情况下获取泛型类型对象的属性
【发布时间】:2014-10-23 21:58:25
【问题描述】:

我需要在不知道具体类型的情况下查看泛型对象的属性:

foreach(var n in Nodes)
{
     if(n.GetType().GetGenericTypeDefinition() == typeof(VariableNode<>))
     {
          if((n as VariableNode<>).Variable == myVar) //obviously this does not work
          {
               toRemove.Add(n);
          }
     }
}

那么,检查“变量”属性的最优雅的方法是什么? (变量是引用类型)

谢谢!

编辑:

节点定义:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using KSPComputer.Types;
using KSPComputer.Connectors;
namespace KSPComputer.Nodes
{

    [Serializable]
    public abstract class Node
    {
        public SVector2 Position;
        public int InputCount
        {
            get
            {
                return inputs.Count;
            }
        }
        public int OutputCount
        {
            get
            {
                return outputs.Count;
            }
        }
        public FlightProgram Program { get; private set; }
        private Dictionary<string, ConnectorIn> inputs;
        private Dictionary<string, ConnectorOut> outputs;
        public KeyValuePair<string, ConnectorIn>[] Inputs
        {
            get
            {
                return inputs.ToArray();
            }
        }
        public KeyValuePair<string, ConnectorOut>[] Outputs
        {
            get
            {
                return outputs.ToArray();
            }
        }
        public Node()
        {
            Position = new SVector2();
            inputs = new Dictionary<string, ConnectorIn>();
            outputs = new Dictionary<string, ConnectorOut>();
        }
        internal virtual void Init(FlightProgram program)
        {
            Program = program;
            OnCreate();
        }
        protected void In<T>(string name, bool allowMultipleConnections = false)
        {
            var connector = new ConnectorIn(typeof(T), allowMultipleConnections);
            connector.Init(this);
            inputs.Add(name, connector);
        }
        protected void Out<T>(string name, bool allowMultipleConnections = true)
        {
            var connector = new ConnectorOut(typeof(T), allowMultipleConnections);
            connector.Init(this);
            outputs.Add(name, connector);
        }
        protected void Out(string name, object value)
        {
            ConnectorOut o;
            if (outputs.TryGetValue(name, out o))
            {
                if (o.Connected)
                {
                    o.SendData(value);
                }
            }
        }
        protected ConnectorOut GetOuput(string name, bool connected = true)
        {
            ConnectorOut o;
            if (outputs.TryGetValue(name, out o))
            {
                if (o.Connected || !connected)
                {
                    return o;
                }
            }
            return null;
        }
        protected ConnectorIn In(string name)
        {
            ConnectorIn o;
            if (inputs.TryGetValue(name, out o))
            {
                return o;
            }
            return null;
        }
        public void UpdateOutputData()
        {
            RequestInputUpdates();
            OnUpdateOutputData();
        }
        protected virtual void OnUpdateOutputData()
        { }
        protected virtual void OnCreate()
        { }
        protected void RequestInputUpdates()
        {
            foreach (var i in inputs.Values)
            {
                i.FreshData = false;
            }
            foreach (var i in inputs.Values)
            {
                if (!i.FreshData)
                {
                    i.RequestData();
                }
            }
        }
        public IEnumerable<Connector> GetConnectedConnectors()
        {
            return (from c in inputs.Values where c.Connected select c as Connector).Concat(from c in outputs.Values where c.Connected select c as Connector);
        }
        public IEnumerable<Connector> GetConnectedConnectorsIn()
        {
            return (from c in inputs.Values where c.Connected select c as Connector);
        }
        public IEnumerable<Connector> GetConnectedConnectorsOut()
        {
            return (from c in outputs.Values where c.Connected select c as Connector);
        }
    }
}

VariableNode的定义:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using KSPComputer;
using KSPComputer.Nodes;
using KSPComputer.Connectors;
using KSPComputer.Variables;
namespace KSPComputer.Nodes
{
    [Serializable]
    public class VariableNode<T> : ExecutableNode
    {
        internal Variable Variable { get; private set; }
        internal void SetVariable(Variable variable)
        {
            this.Variable = variable;
        }
        protected override void OnCreate()
        {
            In<T>("Set");
            Out<T>("Get");
        }
        protected override void OnExecute(ConnectorIn input)
        {
            Variable.Value = In("Set").Get<T>();
            ExecuteNext();
        }
        protected override void OnUpdateOutputData()
        {
            Out("Get", Variable.Value);
        }
    }
}

【问题讨论】:

  • 你能提供更多关于该代码的上下文吗?我会建议一个通用类型约束......但没有更多上下文我不确定这是否合适。
  • 不幸的是,泛型类型约束不适用。你想看什么?
  • NodeVariableNode&lt;&gt; 的定义会很好。

标签: c# generics types properties get


【解决方案1】:

看来你应该可以使用反射了:

foreach(var n in Nodes)
{
     if(n.GetType().GetGenericTypeDefinition() == typeof(VariableNode<>))
     {
          if(n.GetType().GetProperty("Variable").GetValue(n, null) == myVar) 
          {
               toRemove.Add(n);
          }
     }
}

【讨论】:

  • 编译成功。出于兴趣,为什么 GetValue 需要 n 作为参数,即使它已经在 n 的属性上调用? (PS:测试需要一段时间,我会在确认后尽快添加答案!)
  • @pixartist 这是因为你得到了一个PropertyInfo 类型的对象,它对调用它的对象一无所知。 GetValue 表示“从该类型的实例化对象中获取该属性的值”。
【解决方案2】:

另一种解决方案是为您的 VariableNode 定义一个非泛型基类,然后您可以将非泛型属性放在那里,最后您可以轻松地将节点转换为基类或接口并获取属性的值。拥有一个非泛型基是很流行的做法。

【讨论】:

  • 是的,我考虑过这一点,但这会使调用泛型方法在 *** 中很痛苦(In、Out 和 Get)。编辑:好吧,是的,非通用 BASE 类。是的,但在这种情况下,这会使事情复杂化。我更喜欢这里的反射方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-19
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 2017-03-11
  • 1970-01-01
  • 2013-03-05
相关资源
最近更新 更多