5

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: Dynamically Append Code to a method .Net-Core

johnny 5
  • 19,893
  • 50
  • 121
  • 195

2 Answers2

1

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
}

SolessChong
  • 3,370
  • 8
  • 40
  • 67
0

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.

Tarazed
  • 1,707
  • 1
  • 7
  • 22
  • No, I cannot change the code, this needs to be replaced internally at the assembly level. This should be replaced for the assemblies loaded into reference as well – johnny 5 Apr 06 '23 at 18:23
  • 2
    @johnny5 I see, well as far as I am aware I don't think that is possible, and I think it would likely be a huge security flaw if it were. It would open the door to code injection. – Tarazed Apr 06 '23 at 18:27
  • this is 100% possible, I've done it on a simpler level before see my edits for this question https://stackoverflow.com/questions/59417746/dynamically-append-code-to-a-method-net-core – johnny 5 Apr 07 '23 at 14:21