如何通过反射获取非执行程序集中类的属性的值

时间:2014-01-29 23:31:13

标签: c# .net reflection

我在非执行程序集中获取text属性的值时遇到了麻烦;我通过反射从磁盘读取一个程序集,然后我获得程序集中的所有类来搜索由win表单设计器初始化的windows表单类中的Text属性。到目前为止,我有以下代码:

static void Main(string[] args)
{
    Assembly asm = Assembly.LoadFrom(Path.Combine(path, "Assembly.exe"));
    PropertyInfo[] props;
    foreach (Type t in asm.GetTypes())
    {
        var value = t.GetProperty("Text").GetValue(/*Not sure what to put here*/)
    }
}

这就是设计师生成表格的方式

    Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None
    Me.BackColor = System.Drawing.Color.FromArgb(CType(CType(0, Byte), Integer), CType(CType(128, Byte), Integer), CType(CType(128, Byte), Integer))
    Me.ClientSize = New System.Drawing.Size(234, 181)
    Me.Cursor = System.Windows.Forms.Cursors.Default
    Me.Font = New System.Drawing.Font("Arial", 8.25!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
    Me.ForeColor = System.Drawing.SystemColors.WindowText
    Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog
    Me.Location = New System.Drawing.Point(581, 222)
    Me.MaximizeBox = False
    Me.MinimizeBox = False
    Me.Name = "winform"
    Me.RightToLeft = System.Windows.Forms.RightToLeft.No
    Me.StartPosition = System.Windows.Forms.FormStartPosition.Manual
    Me.Text = "Title"
    Me.fraDías.ResumeLayout(False)
    Me.ResumeLayout(False)

请记住,程序集在磁盘上并且没有执行,并且我想要检索每个winform的Text属性的值(我想它应该是在程序集中硬编码的某个地方,因为它是由winforms设计器生成的)

请告诉我这是否可行,谢谢!

3 个答案:

答案 0 :(得分:2)

你的要求是矛盾的,当你通过反射加载aseembly,并实例化一个对象或尝试获取属性值时,会发生一些代码开始运行,没有办法解决这个问题。

请记住,属性只是一对方法的“语法糖”,即getter和setter。它们的当前值只不过是getter方法返回的值,当你改变它的值时,你实际上正在调用它的setter方法。因此,要检索属性值,您必须运行一些代码,即使它是一个简单的get方法。

我想也许你的困惑来自于你正在使用设计师来创建表单。特别是对于WinForms设计器(例如WPF有很大不同),它所做的只是为您自动生成一些代码。设置属性,放置和移动控件,在幕后发生的是它编写的代码在运行时复制您的操作,特别是它编码InitializeComponent方法。调用构造函数时会设置不动产值(然后调用InitializeComponent),然后您可以使用许多属性读取/更改。

您需要阅读的那些设计器属性是那些在某种形式的元数据中被硬编码的,因此它只是作为数据读取而不是作为代码执行的结果。 WinForms并非如此,因为它将表单“保存”为代码。

答案 1 :(得分:1)

您需要该类型的实例对象来获取属性的值。 看起来您只想检查类型是否具有“Text”属性。您可以通过检查确定 bool hasTextProperty = t.GetProperty(“Text”)!= null;

答案 2 :(得分:1)

您无法读取尚未实例化的类的属性!您缺少的参数是您的类型的实例。

在访问其成员之前,您必须使用object o = Activator.CreateInstance(type);创建该类型的实例(除非它们是静态的)。


您的问题与如何在运行时加载加载项(插件)有关。 以下是我制作插件加载器的方法。下面,我将解释如何使其适应您的问题。加载项必须在我的示例中实现IAddIn接口。 IAddIn的定义完全免费。您可以这样定义:

public interface IAddIn
{
    bool OnLoad();

    string Version { get; set; }
    string Text { get; set; }
}

这使您可以访问没有反射的成员。

public class AddInLoader
{
    // Loads all non abstract types implementing IAddIn in all DLLs found in a folder.
    public IList<IAddIn> Load(string folder)
    {
        var addIns = new List<IAddIn>();
        string[] files = Directory.GetFiles(folder, "*.dll");
        foreach (string file in files) {
            addIns.AddRange(LoadFromAssembly(file));
        }
        return addIns;
    }

    // Loads all non abstract types implementing IAddIn found in a file.
    private static IEnumerable<IAddIn> LoadFromAssembly(string fileName)
    {
        Assembly asm = Assembly.LoadFrom(fileName);
        string addInInterfaceName = typeof(IAddIn).FullName;
        foreach (Type type in asm.GetExportedTypes()) {
            Type interfaceType = type.GetInterface(addInInterfaceName);
            if (interfaceType != null &&
               (type.Attributes & TypeAttributes.Abstract) != TypeAttributes.Abstract){
                IAddIn addIn = (IAddIn)Activator.CreateInstance(type);
                addIn.Version = asm.GetName().Version.ToString();
                yield return addIn;
            }
        }
    }
}

现在您可以加载和访问加载项,如下所示:

var loader = new AddInLoader();
IList<IAddIn> addIns = loader.Load(folderPath);
foreach (IAddIn addIn in addIns) {
    if (addIn.OnLoad()) {
        Console.WriteLine("Version = {0}, Text = {1}", addIn.Version, addIn.Text);
    }
}

在运行时阅读表单标题:

您可以轻松调整此示例。不是搜索实现接口的类型,而是搜索从System.Windows.Forms.Form派生的类型。

private static IEnumerable<Form> LoadFormsFromAssembly(string fileName)
{
    Assembly asm = Assembly.LoadFrom(fileName);
    foreach (Type type in asm.GetExportedTypes()) {
        if (typeof(Form).IsAssignableFrom(type) &&
           (type.Attributes & TypeAttributes.Abstract) != TypeAttributes.Abstract) {
            Form form = (Form)Activator.CreateInstance(type);
            yield return form;
        }
    }
}

现在你可以得到这样的表格文本:

var forms = LoadFormsFromAssembly(path);
foreach (Form frm in forms) {
    Console.WriteLine(frm.Text);
}

注意:您必须实例化表单,但不需要打开(显示)它们。仅当表单具有默认构造函数(即不带参数的构造函数)时,代码才有效。