替换程序集级别的类,以便所有引用都调用新的实现。

huangapple go评论64阅读模式
英文:

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&lt;int&gt; { 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&lt;T&gt; : List&lt;T&gt;
    {
        // 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 == &quot;System.Generic.Collections.List&quot;)
        {
            // Load your custom assembly and return it
            return LoadFromAssemblyPath(&quot;path/to/MyAssembly.dll&quot;);
        }
        
        // 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) =&gt; customResolver.Load(assemblyName);
    
    // Your application code
}

答案2

得分: 0

这将在未来引起维护混乱和困扰。我所知道的与您所要求的最接近的东西是 using alias

using MyList = System.Generic.Collections.List&lt;int&gt;;
MyList fooList = new MyList();  // 这将创建一个 System.Generic.Collections.List&lt;int&gt;

然而,我建议尽量为您的类使用不同的名称。这样更清晰,也使您的代码易于维护。在未来的某个时候,有人(可能是您自己)会查看您的 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&lt;int&gt;;
MyList fooList = new MyList();  // This creates a System.Generic.Collections.List&lt;int&gt;

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.

huangapple
  • 本文由 发表于 2023年4月7日 01:53:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/75952410.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定