首页 > 解决方案 > 使用匿名函数初始化委托

问题描述

我有一些以各种模型存在的硬件,并且正在编写可以使用各种 GUI 控制它的软件。我有一个表示硬件的类,它具有电压、速率、大小等属性。我想通过创建如下所示的类来简化对这些属性的访问:

    public class CProperty
    {
        public CProperty(string name, Func<object> get, Action<object> set)
        {
            this.name = name;
            this.get = get;
            set = set;
        }
        private string name;
        public Func<object> get;
        public Action<object> set;
        private object value;
    }

然后我可以初始化一个数组,如下所示:

    public CProperty[] Properties = new CProperty[]
    {
        new CProperty(
            "name1",
            new Func<float>(() => value),
            new Action<float>((v) => value = v)
            ),
    };

然后可以将该数组制作成一个带有索引器的集合类,该索引器使用属性名称作为索引。但是当我尝试这样做时,在数组初始化中,字段“值”不在 set 和 get 函数的初始化程序的范围内,我不明白为什么。

标签: c#anonymous-function

解决方案


您不能将 a 转换Func<float>为 a ,Func<object>也不能将 a 转换Action<float>Action<object>。这是因为协变和逆变不能很好地与值类型一起使用(最后,协变和逆变是花招,不是类型之间的真正转换,因此要求两种类型具有相同的内存布局......参考是一个引用,因此很容易在两个引用之间进行协变/逆变,但是 a是一个值类型,这与作为一个引用类型的 afloat非常不同)object

CProperty在这两种情况下,您都应该向Func/Action, like中添加一个类型的参数Func<CProperty, float>(cp => cp.value),但value必须是public...这是因为匿名方法是“静态的”,它们无法自由访问this引用,因此您必须将其作为范围...

public class CProperty
{
    public CProperty(string name, Func<CProperty, object> get, Action<CProperty, object> set)
    {
        this.name = name;
        this.get = get;
        this.set = set;
    }
    private string name;
    public Func<CProperty, object> get;
    public Action<CProperty, object> set;
    public object value;
}

var properties = new CProperty[]
{
    new CProperty(
        "name1",
        new Func<CProperty, object>(cp => cp.value),
        new Action<CProperty, object>((cp, v) => cp.value = v)
    ),
};

或者您甚至可以捕获this

public class CProperty
{
    public CProperty(string name, Func<CProperty, Func<object>> get, Func<CProperty, Action<object>> set)
    {
        this.name = name;
        this.get = get(this);
        this.set = set(this);
    }
    private string name;
    public Func<object> get;
    public Action<object> set;
    public object value;
}   

var properties = new CProperty[]
{
    new CProperty(
        "name1",
        cp => new Func<object>(() => cp.value),
        cp => new Action<object>((v) => cp.value = v)
    ),
};

最后,我认为你离你想要的还很远……你必须和CProperty班级一起回到设计板。


推荐阅读