Ali*_*lix 5 c# notifications field identifier magic-string
我正在编写一个系统,它是程序员应用程序的基础,需要检测他们对某些数据的访问.我几乎可以使用属性这样做,如下所示:
public class NiceClass {
public int x { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后我进入并调整get和set访问器,以便他们适当地处理访问.但是,这要求用户(应用程序编程人员)将其所有数据定义为属性.
如果用户想要使用具有"正常"字段的预先存在的类(而不是属性),我无法检测到这些访问.例:
public class NotSoNiceClass {
public int y;
}
Run Code Online (Sandbox Code Playgroud)
我无法检测到访问y.但是,我想允许使用预先存在的类.作为折衷方案,用户有责任在访问此类数据时通知我.例如:
NotSoNiceClass notSoNice;
...
Write(notSoNice.y, 0); // (as opposed to notSoNice.y = 0;)
Run Code Online (Sandbox Code Playgroud)
这样的事情.相信我,我已经非常彻底地研究了这一点,甚至直接分析字节码以检测访问因可能的间接性等而不可靠.我确实需要用户通知我.
现在我的问题是:你能推荐一种"优雅"的方式来执行这些通知吗?(是的,我知道这种情况一开始并不"优雅";我试图不让它变得更糟;)).你会怎么做?
这对我来说是个问题,因为实际上情况是这样的:我有以下课程:
public class SemiNiceClass {
public NotSoNiceClass notSoNice { get; set; }
public int z { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
如果用户想要这样做:
SemiNiceClass semiNice;
...
semiNice.notSoNice.y = 0;
Run Code Online (Sandbox Code Playgroud)
他们必须做这样的事情:
semiNice.Write("notSoNice").y = 0;
Run Code Online (Sandbox Code Playgroud)
哪里Write会返回克隆notSoNice,这就是我想让set访问者做的事情.但是,使用字符串非常难看:如果稍后他们重构字段,他们将不得不重新访问它们Write("notSoNice")并更改字符串.
我们如何识别该领域?我只能想到字符串,整数和枚举(即再次注入).但:
NOT_SO_NICE和Z,即,字段SemiNiceClass)容易重构,但它们要求用户为每个类(SemiNiceClass等等)编写枚举,并为该类的每个字段赋值.它很烦人.我不希望他们恨我;)那么,为什么,我听到你问,我们不能这样做(下图)?
semiNice.Write(semiNice.notSoNice).y = 0;
Run Code Online (Sandbox Code Playgroud)
因为我需要知道正在访问哪个字段,并且semiNice.notSoNice不识别字段.这是该领域的价值,而不是领域本身.
叹.我知道这很难看.相信我 ;)
我非常感谢你的建议.
提前致谢!
(另外,我无法想出这个问题的好标签.如果你有更好的想法,请告诉我,我会编辑它们)
编辑#1: Hightechrider的建议:表达式.
我不知道Write(x =>semiNice.y, 0)是不是基于我为我的问题(SemiNiceClass等等)编写的类,或者它只是一个例子,但如果它是前者它与结构不匹配:那里没有y字段SemiNiceClass.你的意思是Write(x =>semiNice.notSoNice.y, 0)?
我不确定你对我的意思是什么...我会发布我写的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Test.MagicStrings {
public class MagicStringsTest {
public static void Main(string[] args) {
SemiNiceClass semiNice = new SemiNiceClass();
// The user wants to do: semiNice.notSoNice.y = 50;
semiNice.Write(x => semiNice.notSoNice.y, 50);
}
}
public class SemiNiceClass {
public NotSoNiceClass notSoNice { get; set; }
public int z { get; set; }
public SemiNiceClass() {
notSoNice = new NotSoNiceClass();
}
public void Write(Func<object, object> accessor, object value) {
// Here I'd like to know what field (y, in our example) the user wants to
// write to.
}
}
public class NotSoNiceClass {
public int y;
}
}
Run Code Online (Sandbox Code Playgroud)
我如何获得该信息Write?我找不到任何方法从中提取出来的信息Func<,>.另外,为什么写semiNice.Write(x => semiNice.notSoNice.y, 50);而不是semiNice.Write(() => semiNice.notSoNice.y, 50);,因为我们没有使用x任何东西?
谢谢.
编辑#2: Hans Passant的建议:用属性替换字段.
这是我原本打算做的,但重新编译不是一种选择.
编辑#3:Ben Hoffstein的建议:动态代理; 李林甫.
我已经深入研究了这个问题,而且由于相对复杂的原因我无法使用它.这可能太长了解释,但请放心:如果我可以使用它,我会的.它比我目前的解决方案更加整洁.
使用表达式,例如 Write(x =>semiNice.y, 0)
这种技术经常被用作避免魔术字符串的一种方法。
例如
public void Write<T,U>(T source, Expression<Func<T, U>> lambda, U value)
{
var body = lambda.Body as MemberExpression;
string memberName = body.Member.Name;
if (body.Member.MemberType == MemberTypes.Field)
{
(body.Member as FieldInfo).SetValue(source, value);
}
else if (body.Member.MemberType == MemberTypes.Method)
{
(body.Member as MethodInfo).Invoke(source, new object[]{value});
}
Console.WriteLine("You wrote to " + memberName + " value " + value);
}
Run Code Online (Sandbox Code Playgroud)