英文:
Replace a class at the assembly level so all references call a new implementation
问题
我想在汇编级别替换一个类,以便所有引用都调用一个新的实现。假设我有一个在整个项目中使用的通用类,比如System.Generic.Collections.List
。
我的项目引用其他依赖于List
的程序集。
现在假设我想在任何调用它的地方使用我的版本的List
。
var values = new List<int> { 1, 2, 3, 4, 5 }
如何替换一个类,以便我不必在我的代码中更新任何引用,或者可以在一个位置完成?
我记得有元数据伙伴类之类的东西,是否可以使用全局预处理指令来覆盖?我依稀记得用过类似这样的语法来实现某种功能:System.Generic.Collections.List::MyAssembly.List
我想以一种"鸭子类型"的方式替换它,即底层类不一定需要继承自原始类,但我应该以相同的方式公开所有方法。
**注意:**我需要以全局方式解决这个问题,通过反射或配置的单一入口点。
在过去,我已经做过一些动态替换方法的事情,参见:https://stackoverflow.com/questions/59417746/dynamically-append-code-to-a-method-net-core
英文:
I would like to replace a class at the assembly level so all references call a new implementation. Lets say I have common class used in assemblies throughout my project such as
System.Generic.Collections.List
My project references other assemblies who rely on List
as well.
Now lets say I want to use my version of List
Where ever this is called.
var values = new List<int> { 1, 2, 3, 4, 5 }
How can replace a class on the assembly level so I don't have to update any references in my code or so that it can be done in a single location.
I remember there are metadata buddy classes and things like that is it possible to override using a global pragma? I vaguely remember using syntax like this for something: System.Generic.Collections.List::MyAssembly.List
I would like to replace this in a duck-typed
way where the underly class doesn't nessecarily have to inherit from the original but I should have all the methods exposed in the same manner
Note: I need to resolve this in a global manner, a single entry point via reflection or configuration.
I've already done things in the past to dynamically replace methods, see: https://stackoverflow.com/questions/59417746/dynamically-append-code-to-a-method-net-core
答案1
得分: 1
没有什么好的方法,但这里有一个解决方法。
// MyAssembly.dll
namespace MyNamespace
{
public class MyList<T> : List<T>
{
// 你的自定义实现
}
}
并且像这样的解析器
using System.Reflection;
using System.Runtime.Loader;
public class CustomAssemblyResolver : AssemblyLoadContext
{
protected override Assembly Load(AssemblyName assemblyName)
{
// 检查请求的程序集是否是目标程序集
if (assemblyName.Name == "System.Generic.Collections.List")
{
// 加载你的自定义程序集并返回它
return LoadFromAssemblyPath("path/to/MyAssembly.dll");
}
// 回退到默认行为
return Default.LoadFromAssemblyName(assemblyName);
}
}
并注册它:
using System.Runtime.Loader;
static void Main(string[] args)
{
// 注册自定义程序集解析器
var customResolver = new CustomAssemblyResolver();
AssemblyLoadContext.Default.Resolving += (context, assemblyName) => customResolver.Load(assemblyName);
// 你的应用程序代码
}
请注意,这些是C#代码示例,不包括在代码中的文本部分。
英文:
Not some good way but here's a workaround.
// MyAssembly.dll
namespace MyNamespace
{
public class MyList<T> : List<T>
{
// Your custom implementation
}
}
And resolver like this
using System.Reflection;
using System.Runtime.Loader;
public class CustomAssemblyResolver : AssemblyLoadContext
{
protected override Assembly Load(AssemblyName assemblyName)
{
// Check if the requested assembly is the target assembly
if (assemblyName.Name == "System.Generic.Collections.List")
{
// Load your custom assembly and return it
return LoadFromAssemblyPath("path/to/MyAssembly.dll");
}
// Fallback to the default behavior
return Default.LoadFromAssemblyName(assemblyName);
}
}
And register it:
using System.Runtime.Loader;
static void Main(string[] args)
{
// Register the custom assembly resolver
var customResolver = new CustomAssemblyResolver();
AssemblyLoadContext.Default.Resolving += (context, assemblyName) => customResolver.Load(assemblyName);
// Your application code
}
答案2
得分: 0
这将在未来引起维护混乱和困扰。我所知道的与您所要求的最接近的东西是 using alias
。
using MyList = System.Generic.Collections.List<int>;
MyList fooList = new MyList(); // 这将创建一个 System.Generic.Collections.List<int>
然而,我建议尽量为您的类使用不同的名称。这样更清晰,也使您的代码易于维护。在未来的某个时候,有人(可能是您自己)会查看您的 List,它不是 System.Generic.Collections.List,会感到非常困惑。
不过,您可以让您的自定义列表实现 IList,这是一种更可取的方法。
英文:
This is going to cause maintenance confusion and headache down the road. The closest thing I know of to what you are asking for is a using alias
.
using MyList = System.Generic.Collections.List<int>;
MyList fooList = new MyList(); // This creates a System.Generic.Collections.List<int>
However, my recommendation whenever possible is to just use a different name for your classes. It's more clear and keeps your code maintainable. Somewhere down the road, someone (possibly you) is going to look at your List that's not a System.Generic.Collections.List and get really confused.
You can, however, have your custom list implement IList, which is a preferred approach.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论