代码之家  ›  专栏  ›  技术社区  ›  Sean Edwards

如何从泛型类型获取属性访问器的委托?

  •  2
  • Sean Edwards  · 技术社区  · 16 年前

    我目前正在构建一个节点编辑器( as in Blender )并且无法从泛型类型获取属性访问器的委托。到目前为止的问题 here 给我带来了最接近的,但我有一个问题,我认为这与一般对象的类型特别相关。

    作为参考,“节点”与对象同义,“端口”与属性同义。

    这是违规代码,它是 Node 班级。这个 NodePort 类是一个属性,可以对属性进行设置,以提供属性的详细信息(如人类可读的名称和数据流方向)。

    public void SetTarget<T>(T Target)
    {
        //TODO: Finish clearing old IOs (if any)
        Inputs.Clear();
        Outputs.Clear();
    
        //Keep track of the current target of this node.
        ThisTarget = Target;
    
        PropertyInfo[] pinfo = Target.GetType().GetProperties();
    
        foreach (PropertyInfo property in pinfo)
        {
            Attribute[] attrs = Attribute.GetCustomAttributes(property);
            foreach (Attribute attribute in attrs)
            {
                // If the property has a NodePort attribute, it's specifically requesting to be available as a port on the node.
                if (attribute is NodePort)
                {
                    NodePort PortDetails = (NodePort)attribute;
    
                    if (PortDetails.Direction == NodePort.NodePortDirection.PORT_INPUT)
                    {
                        // This line throws an ArgumentException, and the only message is "Error binding to target method."
                        NodeInput<T>.SetValue Setter = (NodeInput<T>.SetValue)Delegate.CreateDelegate(typeof(NodeInput<T>.SetValue), (T)Target, property.GetSetMethod());
                        AddInput(Setter, PortDetails.CommonName);
                    }
                    else if (PortDetails.Direction == NodePort.NodePortDirection.PORT_OUTPUT)
                    {
                        // Same exception here.
                        NodeOutput<T>.GetValue Getter = (NodeOutput<T>.GetValue)Delegate.CreateDelegate(typeof(NodeOutput<T>.GetValue), (T)Target, property.GetGetMethod());
                        AddOutput(Getter, PortDetails.CommonName);
                    }
                }
            }
    
        }
    }
    

    NodeOutput<T>.GetValue NodeInput<T>.SetValue 定义如下:

    public delegate T GetValue();
    public delegate void SetValue(T value);
    

    在…中 NodeOutput NodeInput 分别。

    有没有人有为属性访问器创建委托的经验?知道当所讨论的类型是泛型时它可能有什么不同吗?

    2 回复  |  直到 16 年前
        1
  •  1
  •   itowlson    16 年前

    我想你这里的类型不匹配。在例外行的第一行中, setter 声明为类型 NodeInput<T> ,这意味着它是一个获取t并返回void的方法。但是您要分配给的方法 设定器 是property.getsetMethod(),它将是一个获取property.propertyType并返回void的方法。这将导致异常,除非幸运的是,property.propertytype与t相同。对于 getter 在异常行的第二行。

    我怀疑您不能使用泛型来处理此问题,因为您在编译时不知道property.property type,所以不能将该类型作为泛型参数传递(因为除非使用type.makeGenericType,否则必须在编译时指定泛型参数)。

        2
  •  1
  •   Marc Gravell    16 年前

    要创建属性访问器的委托,只需使用 GetGetMethod GetSetMethod 你能解释一下它在哪里坏了吗?

    一个简单的例子:

    using System;
    class Foo<T>
    {
        public T Value { get; set; }
    }
    static class Program
    {
        static void Main()
        {
            var obj = new Foo<int> { Value = 123 };
            var prop = obj.GetType().GetProperty("Value");
            Func<Foo<int>, int> getter = (Func<Foo<int>, int>)
                Delegate.CreateDelegate(
                  typeof(Func<Foo<int>, int>), prop.GetGetMethod());
            int x = getter(obj);
            Console.WriteLine(x);
            Action<Foo<int>, int> setter = (Action<Foo<int>, int>)
                Delegate.CreateDelegate(
                  typeof(Action<Foo<int>, int>), prop.GetSetMethod());
            setter(obj, 321);
            Console.WriteLine(obj.Value);
        }
    }
    

    注意要处理的事情 object 有一些技巧涉及到基类等-或者考虑一些事情,比如 HyperDescriptor ;性能相似,但更简单,因为您只需使用 PropertyDescriptor 对象 (启用后):

    var prop = TypeDescriptor.GetProperties(obj)["Value"];
    object val = prop.GetValue(prop);
    prop.SetValue(prop, 321);
    

    最后一个选择是 Expression ;我介绍了在 表情 在里面 this series .