Получение универсального c интерфейса из сборки вместо использования typeof (Interface) ведет себя непредсказуемо - PullRequest
0 голосов
/ 19 апреля 2020

Мне нужно отфильтровать объекты контейнерной базы на интерфейсе, который они реализуют, одним из них является 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();


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

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

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

    }
  }
}

Любая помощь будет принята с благодарностью.

1 Ответ

0 голосов
/ 20 апреля 2020

на основе комментария @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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...