Мне нужно отфильтровать объекты контейнерной базы по интерфейсу, который они реализуют, один из них — Ibase, это сделает это для известных интерфейсов:

selObjs = container.Where(component => typeof(Ibase).IsAssignableFrom(component.GetType())).ToList();

Но я получаю имена интерфейсов из файла конфигурации, поэтому, поскольку интерфейс не может быть создан, я не могу использовать переменную, прикрепленную к GetType(), кроме того, использование переключателя нецелесообразно, поэтому я получаю Тип интерфейса из сборки.

string interfaceName = "IbaseG<Type>";
interfaceName = $"{interfaceName .Substring(0, interfaceName.IndexOf("<"))}`1";
Type selInterf = AppDomain.CurrentDomain.GetAssemblies()
                    .SelectMany(t => t.GetTypes())
                    .Where(t => String.Equals(t.Name, interfaceName, StringComparison.Ordinal)).ToArray()[0];
selObjs = Container.Where(component => selInterf.IsAssignableFrom(component.GetType())).ToList();


Он отлично работает для неуниверсальных интерфейсов, но если интерфейс является универсальным, интерфейс, полученный из сборки, имеет то же имя и GUID, что и typeof(IbaseG<Type>), но тип и полное имя разные, и он не соответствует использованию IsAssignableFrom.

Это небольшое консольное приложение, которое показывает различия между общим и неуниверсальным интерфейсами.

namespace ConsoleApp {
using System;
using System.Collections.Generic;
using System.Linq;

public interface IbaseG<T> { T Val { get; } }
public class BaseG<T> : IbaseG<T> {
    public T Val { get; }
    public BaseG() { }
}
public class ExtG<T> : BaseG<T> {
    public ExtG() { }
}

public interface Ibase { string Val { get; } }
public class Base : Ibase {
    public string Val { get; }
    public Base() { }
}
public class Ext : Base {
    public Ext() { }
}

class Program {
    static void Main(string[] args) {
        Console.WriteLine("Begin Test");

        bool isAssignable = typeof(IbaseG<string>)
             .IsAssignableFrom(new ExtG<string>().GetType()); //  true

        // Non Generic Type
        Test("Ibase", typeof(Ibase), new Ext());

        // Generic Type
        Test("IbaseG<string>", typeof(IbaseG<string>), new ExtG<string>());

        Console.ReadLine();

    }

    static void Test(string interName, Type typeofType, object obj) {
        if (typeofType.IsGenericType)
            interName = $"{interName.Substring(0, interName.IndexOf("<"))}`1";

        Type assmType = AppDomain.CurrentDomain.GetAssemblies()
                .SelectMany(t => t.GetTypes())
                .Where(t => String.Equals(t.Name, interName, StringComparison.Ordinal))
                .ToArray()[0];

        Dictionary<string, string> results = new Dictionary<string, string>();
        results.Add($"assembly.GetType({assmType.Name})
                       .IsAssignableFrom({obj.GetType().Name}) 1", 
                     (assmType.IsAssignableFrom(obj.GetType()).ToString()));
        results.Add($"typeof({typeofType.Name})
                       .IsAssignableFrom({obj.GetType().Name}) 2", 
                     (typeofType.IsAssignableFrom(obj.GetType()).ToString()));
        results.Add("Same Type", (assmType == typeofType).ToString()); // true
        results.Add("Same Name", (assmType.Name == typeofType.Name).ToString()); // true
        results.Add("Same FullName", (assmType.FullName == typeofType.FullName).ToString()); // true
        results.Add("Same GUID", (assmType.GUID == typeofType.GUID).ToString()); // true

        if (assmType.IsGenericType)
            Console.WriteLine($"Generic Type: {interName} Results");
        else
            Console.WriteLine($"Non Generic Type: {interName} Results");

        foreach (KeyValuePair<string, string> result in results)
            Console.WriteLine($"{result.Key}: {result.Value}");

        Console.WriteLine($"typeof({typeofType.Name}).FullName: {typeofType.FullName}");
        Console.WriteLine($"assembly.GetType({assmType.Name}).FullName: {assmType.FullName}");
        Console.WriteLine($"typeof({typeofType.Name}).GUID: {typeofType.GUID}");
        Console.WriteLine($"assembly.GetType({assmType.Name}).GUID: {assmType.GUID}");
        Console.WriteLine();

    }
  }
}

Любая помощь будет оценена.

c#
0
JoseVeiras 19 Апр 2020 в 05:20
Поскольку «Ibase'1» — это typeof(Ibase<>), вам нужно создать конкретный тип, используя Type.MakeGenericType ... например, typeof(Ibase<>).MakeGenericType(typeof(string)) см. это
 – 
Selvin
19 Апр 2020 в 05:46
Танк за ваш ответ, но в этом случае MakeGenericType заставляет объект «реализовать» интерфейс, и мне нужно проверить, реализует ли объект интерфейс, поэтому решение должно выполнять typeof(IbaseG<String>).IsAssignableFrom( new ExtG<String>()); без чего-то, что может использовать переменную.
 – 
JoseVeiras
20 Апр 2020 в 01:05

1 ответ

На основе комментария @Selvin.

Интерфейс, полученный из сборки, должен быть MakeGenericType того же типа, что и объект:

// ExtG<Type> implements the intreface IbaseG<Type> 
string interName = "IbaseG<Type>";
Type typeofType = typeof(IbaseG<Type>);
object obj = new ExtG<Type>();

if (typeofType.IsGenericType)
    interName = $"{interName.Substring(0, interName.IndexOf("<"))}`1";

Type assmType = AppDomain.CurrentDomain.GetAssemblies()
        .SelectMany(t => t.GetTypes())
        .Where(t => String.Equals(t.Name, interName, StringComparison.Ordinal))
        .ToArray()[0];

if (typeofType.IsGenericType)
    assmType = assmType.MakeGenericType(typeof(Type));

bool test1 = typeof(IbaseG<Type>).IsAssignableFrom(obj.GetType()); //true
bool test2 = (assmType.IsAssignableFrom(obj.GetType())); // true
0
JoseVeiras 20 Апр 2020 в 00:15
Вам нужна рекурсия для fx Ibase<IEnumerable<string>>
 – 
Selvin
20 Апр 2020 в 02:55