通过Visual Studio和C#/VB.NET中的代码生成破解元编程
本文关键字:代码生成 破解 编程 NET VB Studio Visual 通过 | 更新日期: 2023-09-27 17:58:55
我正试图破解一种生成代码的机制,这样我就可以动态地做某些事情,同时保留强类型的好处。
这是我想做的事情的一个例子。我有一个这样的对象:
Class Fruits
Public Property Apple As System.Int32
Public Property Orange As System.Int32
Public Property Kiwi As System.Int32
...quite a few others
Public Property Banana As System.Int32
Public Property Watermelon As System.Int32
Public Property Durian As System.Int32
End Class
我有一些代码可以做到这一点:
Dim dict = myEntity.ToDictionary()
Dim myFruits = {"Apple", "Banana", "Cherry"}
For Each fruit in myFruits
Dim fruitValue = dict(fruit)
doSomething(fruitValue)
Next
换句话说,我有一个强类型类,我想访问它的属性,但这些属性是由代码确定的字符串。
我想避免的问题是,我的Fruits类可能会更改——例如,Apple
属性被删除。这可能是因为它是通过代码生成创建的,也可能是因为我正在重构所以循环中的代码被破坏了,但编译器没有办法警告我这一点。
到目前为止,上面的代码相当于这个:
fruitValue = item.Apple
doSomething(fruitValue)
fruitValue = item.Banana
doSomething(fruitValue)
fruitValue = item.Cherry
doSomething(fruitValue)
如果我有这段代码并删除了Apple
,我会得到一个编译错误,一切都会好起来。
但事实上,我的水果清单可能会有更多的项目和/或由一些复杂的设计时规则决定,所以把它们都写出来会非常乏味和烦人。
我想要的是一种编写代码的方法,该代码在设计时由Visual Studio预处理,以生成内联、类型安全的代码
我想象的是一个系统和语法,我可以指定一个模板,该模板的输入,以及某种AddIn,它可以扫描代码文件,并在部分类文件中生成所需的代码。然后,我可以编写简洁而动态的代码,但要将其扩展为显式属性访问,如果底层对象发生更改,则会导致编译器错误。
所以问题是:如何实现这一点
您可以使用类似的东西来动态获取对象的所有属性:
var fruits = new Fruits();
foreach (var prop in fruits.GetType().GetProperties())
{
// Do stuff here
}
这样,当你更新对象属性时,上面的代码仍然会遍历它们所有的
请参阅msdn了解更多
您可以使用反射。我会创建一个扩展方法来获取属性的值:
public static object GetPropvalue(this object InputObject, string PropertyName)
{
Type type = InputObject.GetType();
PropertyInfo p = type.GetProperty(PropertyName);
if (p != null)
{
return p.GetValue(InputObject);
}
else
{
return null;
}
}
然后你可以做
foreach (var f in myFruits)
{
var fruitValue = myEntity.GetPropValue(f);
if (fruitValue != null)
{
doSomething(fruitValue));
}
}
这个例子将在编译时完成您的场景的工作,而不需要元编程
Public Class Fruits
Public Property Apple As Integer
Public Property Orange As Integer
Public Property Kiwi As Integer
End Class
以及使用NameOf表达式和Fruits
类的伪实例的代码。
Dim dict = myEntity.ToDictionary()
Dim dummy As New Fruits()
Dim myFruits As New List(Of String) From
{
NameOf(dummy.Apple),
NameOf(dummy.Orange),
NameOf(dummy.Kiwi)
}
For Each fruit in myFruits
Dim fruitValue = dict(fruit)
DoSomething(fruitValue)
Next
这将适用于您描述的场景:如果Apple
属性将被删除,编译器将引发一个错误。
但在我看来,这种解决方法看起来更像是代码气味(使用伪实例)。我相信,如果你能更多地讲述你的问题,你会得到更合适的解决方案。