我有一个由我自己构建的.NET程序集,但希望能够在运行时上使用一些较小但任意的属性更改文件重写.DLL。具体来说,我希望能够更改类的属性的属性,以便可以根据情况自定义二进制文件。
为说明起见,我想实现编辑从代码生成的程序集的效果
[SomeAttribute("Name")]
public class MyClass{
...
使新程序集在功能上与
相同[SomeAttribute("Custom Name")]
public class MyClass{
...
此“自定义名称”可以是任何值(在运行时确定)。在运行时可以这样做吗?
需要修改实际.DLL的原因是,它将由无法确定运行时信息(我不控制此过程)的单独进程加载。
到目前为止,实验表明,如果新的“自定义名称”的长度与原始长度相同,则似乎可以正常工作,但是并非如此(即使您编辑指定长度的前一个字节;大概在其中存储了偏移量)该文件)。
编辑:忘记了,解决方案也必须在.NET 2框架下。
答案 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
。