question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Non-generic ExportProvider.GetExports(Type) method missing

See original GitHub issue

Given a Type variable, how can I get its export?

public object Resolve<T>() => exportProvider.GetExportedValue<T>();          // OK
public object Resolve(Type type) => exportProvider.GetExportedValue(type);   // ??

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:15 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
weltkantecommented, May 28, 2019

If you can elaborate on why this is important for you

I cannot speak for the OP, but I had the same requirement a few years ago when I had to implement IServiceProvider through a composition container. I don’t remember how I solved it back then, but I did get it to work via vs-mef at some point. These days I don’t see much usage of IServiceProvider so unfortunately I don’t have this trick in my codebase anymore.

I think if you expose GetContractName publically that should be enough, I think you can just pass object into the generic parameter of e.g. GetExportedValue together with the contract name, something like that already seems to work (unless there is a hidden edge case where it fails?):

public static class ContainerExtensions
{
    private abstract class PartDiscoveryHelper : PartDiscovery
    {
        private PartDiscoveryHelper(Resolver resolver) : base(resolver) { }
        public static string GetContractNameHelper(Type type) => GetContractName(type);
    }

    public static object GetExportedValue(this ExportProvider container, Type type)
    {
        return container.GetExportedValue<object>(PartDiscoveryHelper.GetContractNameHelper(type));
    }
}
0reactions
znakeeyecommented, Jun 7, 2019

I managed to create an extension method for the following method:

IEnumerable<object> GetExportedValues(Type type, string contractName) 

Getting it done for the very much needed GetExported() method is way harder due to the complex conversion needed for the return value. 😢

IEnumerable<Lazy<object, object>> GetExports(Type type, Type metadataViewType, string contractName); 

Source code

public static class ExportProviderExtensions
{
    private static readonly Func<Type, CompiledMethods> createCompiledMethods;
    private static readonly ConcurrentDictionary<Type, CompiledMethods> compiledMethods = new ConcurrentDictionary<Type, CompiledMethods>();

    static ExportProviderExtensions()
    {
        createCompiledMethods = t => new CompiledMethods(t);
    }

    public static IEnumerable<object> GetExportedValues(this ExportProvider exportProvider, Type type, string contractName)
    {
        return GetOrAdd(type).GetExports(exportProvider, contractName);
    }

    private static CompiledMethods GetOrAdd(Type type) => compiledMethods.GetOrAdd(type, createCompiledMethods);

    private class CompiledMethods
    {
        public readonly Func<ExportProvider, string, IEnumerable<object>> GetExports;

        public CompiledMethods(Type type)
        {
            var method = GetMethod(type, typeof(string));

            var instance = Expression.Parameter(typeof(ExportProvider));
            var arguments = method.GetParameters().Select(p => Expression.Parameter(p.ParameterType)).ToArray();
            var parameters = Enumerable.Repeat(instance, 1).Concat(arguments);
            
            var body = Expression.Call(instance, method, arguments.ToArray<Expression>());
            var convert = Expression.Convert(body, typeof(IEnumerable<object>));

            var delegateType = typeof(Func<,,>).MakeGenericType(typeof(ExportProvider), typeof(string), typeof(IEnumerable<object>));
            var lambda = Expression.Lambda(delegateType, convert, parameters).Compile();
            
            GetExports = (Func<ExportProvider, string, IEnumerable<object>>) lambda;
        }

        private static MethodInfo GetMethod(Type type, params Type[] parameters)
        {
            return typeof(ExportProvider)
                .GetMethods()
                .Where(m => m.Name == nameof(ExportProvider.GetExportedValues))
                .Where(m => m.GetGenericArguments().Length == 1)
                .Single(m => ParametersMatch(m, parameters))
                .MakeGenericMethod(type);
        }

        private static bool ParametersMatch(MethodInfo method, Type[] parameters)
        {
            var ps = method.GetParameters();
            if (ps.Length != parameters.Length)
            {
                return false;
            }

            for (int i = 0; i < ps.Length; i++)
            {
                if (parameters[i] == null && ps[i].ParameterType.IsGenericParameter)
                {
                    continue;
                }

                if (ps[i].ParameterType != parameters[i])
                {
                    return false;
                }
            }
            return true;
        }
    }
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - The non-generic method 'IServiceProvider.GetService ...
It means your compiler only has knowledge of the method that takes a type. You could call var incoming = serviceProvider.GetService(typeof( ...
Read more >
ExportProvider.GetExports Method
Gets all exports that match the conditions of the specified import definition and composition. GetExports(Type, Type, String). Gets all the exports with the ......
Read more >
ComposeExportedValue<T> in MEF2 (System.Composition)
Shows how to generate exports on the fly so that they can be injected into constructors of the types that depend on them...
Read more >
https://raw.githubusercontent.com/dotnet/samples/m...
24611 area-Serialization Ignore the type in SGEN if it contains any ... TryGetValue not found out value for other classes: Function | actual...
Read more >
Managed Extensibility Framework - RSSing.com
Bascially I've got a session factory class which imports the fluent configuration and exports new NHibernate ISessions through a function with the attribute ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found