Мне нужно отфильтровать объекты контейнерной базы по интерфейсу, который они реализуют, один из них — 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();
}
}
}
Любая помощь будет оценена.
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
Ibase<IEnumerable<string>>
Похожие вопросы
Новые вопросы
c#
C# (произносится как «see Sharp») — это высокоуровневый мультипарадигменный язык программирования со статической типизацией, разработанный Microsoft. Код C# обычно нацелен на семейство инструментов и сред выполнения Microsoft .NET, которое включает в себя .NET, .NET Framework, .NET MAUI и Xamarin среди прочих. Используйте этот тег для ответов на вопросы о коде, написанном на C#, или о формальной спецификации C#.
typeof(Ibase<>)
, вам нужно создать конкретный тип, используяType.MakeGenericType
... например,typeof(Ibase<>).MakeGenericType(typeof(string))
см. этоtypeof(IbaseG<String>).IsAssignableFrom( new ExtG<String>());
без чего-то, что может использовать переменную.