在汇编级别替换一个类,以便所有引用都调用新的实现

问题描述 投票:0回答:3

我想在汇编级别替换一个类,以便所有引用都调用一个新的实现。可以说我在整个项目的程序集中使用了通用类,例如

System.Generic.Collections.List

我的项目也引用了其他依赖

List
的程序集。

现在假设我想使用我的版本

List
在哪里调用它。

var values = new List<int> { 1, 2, 3, 4, 5 }

如何在程序集级别替换一个类,这样我就不必更新代码中的任何引用,或者可以在一个位置完成它。

我记得有元数据伙伴类和类似的东西可以使用全局 pragma 覆盖吗?我依稀记得使用这样的语法来做某事:

System.Generic.Collections.List::MyAssembly.List

我想以

duck-typed
的方式替换它,其中底层类不必继承原始类,但我应该以相同的方式公开所有方法

注意: 我需要以全局方式解决这个问题,通过反射或配置的单一入口点。

我过去已经做过动态替换方法的事情,请参阅:动态将代码附加到方法.Net-Core

c# .net-assembly castle-dynamicproxy
3个回答
0
投票

这将导致维护混乱和令人头疼的问题。我所知道的最接近你要求的是

using alias
.

using MyList = System.Generic.Collections.List<int>;
MyList fooList = new MyList();  // This creates a System.Generic.Collections.List<int>

但是,我的建议是尽可能为您的类使用不同的名称。它更清晰并使您的代码易于维护。在路上的某个地方,有人(可能是你)会查看你的 List 而不是 System.Generic.Collections.List 并感到非常困惑。

但是,您可以让自定义列表实现 IList,这是一种首选方法。


0
投票

不是什么好方法,但这里有一个解决方法。

// MyAssembly.dll
namespace MyNamespace
{
    public class MyList<T> : List<T>
    {
        // Your custom implementation
    }
}

像这样的解析器

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);
    }
}

并注册它:

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
}


0
投票

您正在寻找的是 .NET 中的“Type Forwarding”。类型转发允许您将对一种类型的引用重定向到另一种类型,而无需更改引用原始类型的代码。正如您所描述的,这可用于在装配级别替换类型。

要使用类型转发,您需要定义一个新的程序集,其中包含一个转发到 List 类的新实现的类型。此类型应使用与原始 List 类相同的命名空间和名称来定义。然后,你需要使用 TypeForwardedToAttribute 指定将原来的 List 类型转发到你定义的新类型。

这是一个如何做到这一点的例子:

  1. 定义一个新程序集,其类型转发到 List 的新实现:
namespace System.Generic.Collections {
    [System.Runtime.CompilerServices.TypeForwardedTo(typeof(MyAssembly.List))]
    public class List<T> : MyAssembly.List<T> {}
}
  1. 在您的代码中,像往常一样引用原始的 List 类:
var values = new List<int> { 1, 2, 3, 4, 5 };
  1. 在运行时,当代码引用 List 类时,
    TypeForwardedToAttribute
    将导致它被重定向到
    List
    的新实现。

注意你定义的新类型应该和原来的List类有相同的公共接口,这样引用List的代码就可以继续使用新的实现而无需修改。

还要注意,类型转发是一种全局机制,因此它会影响所有引用原始 List 类的程序集。如果您只想替换某些程序集中的列表,则需要使用不同的方法,例如程序集绑定重定向或自定义程序集解析器。

© www.soinside.com 2019 - 2024. All rights reserved.