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

C#在运行时以编程方式编辑我的.NET程序集,c#,.net-assembly,.net-2.0,C#,.net Assembly,.net 2.0,我有一个由我自己构建的.NET程序集,但希望能够在运行时使用一些较小但任意的属性更改文件重写.DLL。具体来说,我希望能够更改类属性的属性,以便根据情况自定义二进制文件 为了举例说明,我想实现编辑从代码生成的程序集的效果 [SomeAttribute("Name")] public class MyClass{ ... 这样,新部件的功能与 [SomeAttribute("Custom Name")] public class MyClass{ ... 这个“自定义名称”可以

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

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

[SomeAttribute("Name")]
public class MyClass{
    ...
这样,新部件的功能与

[SomeAttribute("Custom Name")]
public class MyClass{
    ...
这个“自定义名称”可以是任何东西(在运行时确定)。这可以在运行时执行吗

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

到目前为止的实验表明,如果新的“自定义名称”与原始名称的长度相同,则该方法似乎有效,但在其他情况下则无效(即使编辑指定长度的前一个字节;可能文件中某处存储了偏移量)


编辑:忘了提一下,解决方案也需要在.NET 2框架下。

您可以在运行时使用
TypeDescriptor
类添加属性,而不是修改DLL;e、 g

TypeDescriptor.AddAttributes(typeof(MyClass), new SomeAttribute("Custom Name"));
这种方法唯一需要注意的是,纯粹依赖反射的代码将无法读取添加的属性-您必须使用
TypeDescriptor.GetAttributes()
。但是,大多数对属性进行操作的内置.NET Framework方法都知道在运行时添加的元数据


不清楚你真正想做什么()

但是,如果要修改程序集,通常会使用自描述:可以加载现有托管程序集,浏览所有包含的类型,动态修改它们,并将修改后的程序集保存回磁盘

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

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);
    }
}
公共类MyAttribute:Attribute
{
公共MyAttribute(字符串str)
{
参数=str;
}
私有字符串参数;
公共字符串参数{get;}
公共字符串程序集名称
{
得到
{
返回Assembly.GetEntryAssembly().FullName;
}
}
}
[MyAttribute(“你好”)]
班级计划
{
静态void Main(字符串[]参数)
{
var attr=typeof(Program).GetCustomAttribute();
Console.WriteLine(属性参数);
Console.WriteLine(属性AssemblyName);
}
}

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

在.NET2下,您可以安装软件包Mono.Cecil0.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");
AssemblyDefinition assbDef=AssemblyDefinition.ReadAssembly(“x.dll”);
TypeDefinition type=assbDef.MainModule.GetType(“NameSpace.MyClass”).Resolve();
foreach(type.CustomAttributes中的CustomAttribute属性属性)
{
TypeReference argTypeRef=null;
int?索引=null;
for(int i=0;i

它将在程序集中搜索任何具有值
“Name”
的属性参数,并将其值替换为
newName

,我建议您使用另一种方法,在该程序集中创建一个新程序集,并创建一个新的
MyClass
子类,同时更改属性名称。您当前的方法可能不被允许,防病毒软件可能会将其检测为有害行为。@AkashKava我不需要手动重新生成程序集,然后将子类包含在内吗?我需要新名字是任意的;它不能预先制作。我现在不太担心防病毒,因为我完全控制了原始程序集(它不是系统程序集或任何东西),我记不起确切的细节,但是,如果您使用的是有符号的程序集(在生产环境中应该是这样),那么您甚至不能在不使程序集无效的情况下更改任何一位。@Enigmativity是的,这是正确的,现在不需要考虑修改它,可能是您的工具。一般来说,你想做的是一个坏主意。不幸的是,这不是一个选项,dll可以在其他地方(通过不同的进程)调用。它需要更新为所有未来可能使用的dll,而不仅仅是我加载到内存中。我会稍微澄清一下这个问题。关于这个属性的建议很好,不幸的是,这个属性是一个
密封的
类,而且我想更改的值不是虚拟的。很抱歉,我之前忘记提到过这一点,但解决方案需要在.NET 2上运行,将更新问题我将在存档中查看Mono.Cecil的旧版本,它们似乎曾经支持.NET2。