C# 使用匿名函数初始化委托

C# 使用匿名函数初始化委托,c#,anonymous-function,C#,Anonymous Function,我有一些不同型号的硬件,我正在编写软件,用不同的GUI控制它。我有一个表示硬件的类,它具有诸如电压、速率、大小等属性。我想通过创建如下类来简化对这些属性的访问: public class CProperty { public CProperty(string name, Func<object> get, Action<object> set) { this.name = name;

我有一些不同型号的硬件,我正在编写软件,用不同的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;
    }
公共类CProperty
{
公共CProperty(字符串名称、函数获取、操作集)
{
this.name=名称;
this.get=get;
集合=集合;
}
私有字符串名称;
公共职能部门;
公共行动集;
私人客体价值;
}
然后我可以如下初始化一个数组:

    public CProperty[] Properties = new CProperty[]
    {
        new CProperty(
            "name1",
            new Func<float>(() => value),
            new Action<float>((v) => value = v)
            ),
    };
public CProperty[]属性=新CProperty[]
{
新财产(
“名称1”,
新函数(()=>值),
新操作((v)=>value=v)
),
};
然后,可以将该数组制作成一个集合类,其中包含一个使用属性名作为索引的索引器。
但是当我尝试这样做时,在数组初始化中,set和get函数的初始化器中的字段“value”不在范围内,我不明白为什么。

您不能将
Func
转换为
Func
,也不能将
操作
转换为
操作
。这是因为协方差和逆方差不能很好地处理值类型(归根结底,协方差和逆变是一种花招,不是类型之间的真正转换,因此需要两种类型具有相同的内存布局……引用是一种引用,因此在两个引用之间进行协方差/逆变很容易,但
float
是一种值类型,这与
o非常不同对象
是引用类型)

在这两种情况下,您都应该向
Func/Action
添加类型为
CProperty
的参数,例如
Func(cp=>cp.value)
,但是
value
必须是
public
…这是因为匿名方法是“静态的”,它们不能自由访问
引用,因此您必须将其作为参数传递

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

最后,我认为你离你想要的还很远……你必须回到设计板上,使用
CProperty
类。

我不太明白你在这里要实现什么

看看代码,我可以说您正在尝试重新实现一个概念-您有backing field
value
和getter with setter,由代理表示

看看描述

集合类,其索引器使用属性名称作为索引

我可以说,您希望在运行时通过对象的名称访问对象的属性-这可以通过使用

至少,我能回答这部分

但是当我尝试这样做时,在数组初始化中,“value”字段不在set和get函数的初始化器的作用域中,我不明白为什么

正如编译器所建议的,这件事是关于范围的。在这种情况下区分两者是有意义的。 词法作用域或静态作用域是通过程序源代码中的位置来定义的,而动态作用域是建立在实际执行路径上的。C#具有词法作用域,因此,从
CProperty
类外部声明的委托无法访问
value
字段,尽管它们实际上是在内部调用的

value
是一个字段,它位于
CProperty
类的范围内,因此它仅对该类的成员可见。外部世界可以通过
CProperty
实例访问此字段(但仅当您将字段
公开时)


这有什么意义?我的意思是你可以在
CProperty
中定义
get
set
,它们是“经典”的获取者和设置者。你为什么要在“外部”定义它们?不能将
Func
转换为
Func
,也不能将
操作
转换为
操作
协方差和逆变换与值类型不匹配。
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)
    ),
};
var prop = new CProperty(/*ctor parameters*/)
var value = prop.value;