C#:Как найти и создать экземпляры, удовлетворяющие ограничениям нескольких типов
-
19-09-2019 - |
Вопрос
Допустим, у меня есть универсальный метод с несколькими ограничениями типа, это this:
public static void DoSomethingAwesome<T>(T thing)
where T : IThing, IAwesome, IComparable<T>
{
...
}
Сейчас же....как я могу, используя отражение, создать что-то, что я могу отправить туда?
Если бы это было только одно ограничение, я знаю, что могу сделать это следующим образом:
var types = assembly
.GetTypes()
.Where(typeof (IThing).IsAssignableFrom)
foreach(var t in types)
DoSomethingAwesome((IThing) Activator.CreateInstance(t));
Но на самом деле я не могу выполнить приведение к нескольким интерфейсам...как, черт возьми, я могу это решить?Вы могли бы сказать, что сейчас я здесь в значительной степени потерян :P
Название получилось довольно длинным и сложным, так как я не был уверен, как это назвать, пожалуйста, улучшите, если сможете
Решение
Чтобы добавить к ответам Рида и Лорен о поиске подходящих типов, обратите внимание, что вы все равно не сможете вызвать DoSomethingAwesome путем приведения, потому что, как вы обнаружили, компилятор не предоставляет способа приведения созданного объекта к нескольким интерфейсам.У вас есть два варианта:
Создайте новый интерфейс IAwesomeComparableThing, который является производным от IThing, IAwesome и IComparable<T>, пусть ваши типы реализуют это и приведут к этому.
Вызовите DoSomethingAwesome с помощью отражения.Чтобы сделать это, вам будет нужно получить MethodInfo для DoSomethingAwesome универсального метода, затем вызовите MethodInfo.Создайте genericMethod с вашим типом, который реализует все три интерфейса.
Пример из (2):
Type type = sometype; // For example found using reeds method
MethodInfo mgeneric = typeof(Awesomeiser).GetMethod("DoSomethingAwesome");
MethodInfo mspecific = mgeneric.MakeGenericMethod(new [] { type });
mspecific.Invoke(null, new [] { type });
Другие советы
Я предполагаю, что есть какая-то причина, по которой ты не можешь этого сделать
var types = assembly
.GetTypes()
.Where(typeof (IThing).IsAssignableFrom && typeof (IAwesome).IsAssignableFrom))
Вам нужен тип, который можно назначить из всех ваших ограничений.Первые два просты, но третий немного сложнее:
// Using
static bool IsIComparable(Type thing)
{
foreach (Type interfaceType in thing.GetInterfaces())
{
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof (IComparable<>))
{
Type[] arguments = interfaceType.GetGenericArguments();
if (arguments.Length == 1)
{
if (arguments[0] == thing)
return true;
}
}
}
return false;
}
// This returns an enumerable of compatible types:
var types = assembly.GetTypes().Where( t =>
typeof(IThing).IsAssignableFrom(t) &&
typeof(IAwesome).IsAssignableFrom(t) &&
IsIComparable(t) );