C#在运行时以编程方式编辑.NET程序集

时间:2018-07-24 06:21:10

标签: c# .net-assembly .net-2.0

我有一个由我自己构建的.NET程序集,但希望能够在运行时上使用一些较小但任意的属性更改文件重写.DLL。具体来说,我希望能够更改类的属性的属性,以便可以根据情况自定义二进制文件。

为说明起见,我想实现编辑从代码生成的程序集的效果

[SomeAttribute("Name")]
public class MyClass{
    ...

使新程序集在功能上与

相同
[SomeAttribute("Custom Name")]
public class MyClass{
    ...

此“自定义名称”可以是任何值(在运行时确定)。在运行时可以这样做吗?

需要修改实际.DLL的原因是,它将由无法确定运行时信息(我不控制此过程)的单独进程加载。

到目前为止,实验表明,如果新的“自定义名称”的长度与原始长度相同,则似乎可以正常工作,但是并非如此(即使您编辑指定长度的前一个字节;大概在其中存储了偏移量)该文件)。

编辑:忘记了,解决方案也必须在.NET 2框架下。

3 个答案:

答案 0 :(得分:2)

不清楚您真正想做什么(XY problem?

不过,如果要修改程序集,通常使用Mono.Cecil,它自描述为:您可以加载现有的托管程序集,浏览所有包含的类型,即时修改它们并保存。将修改后的程序集返回到磁盘。

请注意,属性可以在作为参数传递的数据之上还包含额外的数据:

public class MyAttribute : Attribute
{
    public MyAttribute(string str)
    {
        argument = str;
    }

    private string argument;

    public string Argument { get; }

    public string AssemblyName
    {
        get
        {
            return Assembly.GetEntryAssembly().FullName;
        }
    }
}


[MyAttribute("Hello")]
class Program
{
    static void Main(string[] args)
    {
        var attr = typeof(Program).GetCustomAttribute<MyAttribute>();
        Console.WriteLine(attr.Argument);
        Console.WriteLine(attr.AssemblyName);
    }
}

答案 1 :(得分:0)

您可以在运行时使用TypeDescriptor类添加属性,而无需修改DLL。例如

TypeDescriptor.AddAttributes(typeof(MyClass), new SomeAttribute("Custom Name"));

此方法的唯一警告是,仅依赖反射的代码将无法读取添加的属性-您必须使用TypeDescriptor.GetAttributes()。但是,大多数对属性进行操作的内置.NET Framework方法都知道在运行时添加的元数据。

https://msdn.microsoft.com/en-us/library/system.componentmodel.typedescriptor_methods(v=vs.110).aspx

答案 2 :(得分:0)

使用@xanatos的非常有用的建议,我提出了以下解决方案:

在.NET 2下,您可以安装软件包Mono.Cecil 0.9.6.1。

然后,代码如下:

AssemblyDefinition assbDef = AssemblyDefinition.ReadAssembly("x.dll");
TypeDefinition type = assbDef.MainModule.GetType("NameSpace.MyClass").Resolve();
foreach (CustomAttribute attr in type.CustomAttributes)
{
    TypeReference argTypeRef = null;
    int? index = null;
    for (int i = 0; i < attr.ConstructorArguments.Count; i++)
    {
        CustomAttributeArgument arg = attr.ConstructorArguments[i];

        string stringValue = arg.Value as string;
        if (stringValue == "Name")
        {
            argTypeRef = arg.Type;
            index = i;
        }
    }

    if (index != null)
    {
        attr.ConstructorArguments[(int)index] = new CustomAttributeArgument(argTypeRef, newName);
    }
}    
assbDef.Write("y.dll");

这将在程序集中搜索任何值为"Name"的属性参数,并将其值替换为newName