我有一些作为各种模型存在的硬件,我正在编写将使用各种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)
),
};
然后可以将数组转换为具有索引器的集合类,该索引器使用属性名称作为索引。 但是当我尝试这样做时,在数组初始化字段&#34; value&#34;不在set和get函数的初始值设定范围内,我不明白为什么。
答案 0 :(得分:0)
您无法将Func<float>
转换为Func<object>
,也无法将Action<float>
转换为Action<object>
。这是因为协方差和逆变不能很好地与价值类型相匹配(最终协方差和逆变是手法,而不是类型之间的真实转换,因此要求两种类型具有相同的内存布局...... reference是一个引用,因此很容易在两个引用之间进行协方差/逆变,但是float
是一个值类型,它与作为引用类型的object
非常不同)
在这两种情况下,您都应该向CProperty
添加Func/Action
类型的参数,例如Func<CProperty, float>(cp => cp.value)
,但value
必须是public
...这是因为匿名方法是&#34;静态&#34;,他们无法免费访问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
班的设计委员会。
答案 1 :(得分:0)
我不太了解你将在这里实现的目标。
查看代码,我可以说你正在尝试重新实现一个property概念 - 你有支持字段value
和getter用代表表达的setter。
看一下描述,
带有索引器的集合类,该索引器使用属性名称作为索引
我可以说你想在运行时通过名字访问对象的属性 - 这可以使用reflection。
至少,我能够回答这部分
但是当我尝试这样做时,在数组初始化中,字段“value”不在set和get函数的初始化器中,并且我不明白为什么。
正如编译器所说,这件事与范围界定有关。在这种情况下区分Lexical and dynamic scope是有意义的。
词法或静态范围是通过程序源代码中的位置定义的,而动态范围是基于实际执行路径构建的。 C#具有词法作用域,因此,从CProperty
类外部声明的委托不能访问value
字段,尽管它们实际上是在内部调用的。
value
是一个字段,它位于CProperty
类的范围内,因此它仅对此类成员可见。外部世界可以通过CProperty
实例访问此字段(但仅当您创建字段public
时)。
var prop = new CProperty(/*ctor parameters*/)
var value = prop.value;