C#在运行时以编程方式编辑我的.NET程序集
我有一个由我自己构建的.NET程序集,但希望能够在运行时使用一些较小但任意的属性更改文件重写.DLL。具体来说,我希望能够更改类属性的属性,以便根据情况自定义二进制文件 为了举例说明,我想实现编辑从代码生成的程序集的效果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{ ... 这个“自定义名称”可以
[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。