#c# #reflection #valueinjecter
#c# #отражение #valueinjector
Вопрос:
Редактировать
Простая версия этого вопроса такова: если у меня есть некоторые object o
, как бы я проверил, относится ли o к какому-либо типу, который реализует IEnumerable<string>
с отражением? Исходный вопрос гораздо более конкретный, но ответ на приведенный выше был бы столь же хорош. Извините, если я дал слишком много подробностей по этому вопросу
ЗАВЕРШИТЬ РЕДАКТИРОВАНИЕ
Ниже приведен надуманный запрос значения POC. Все работает хорошо, за исключением isCollectionMapping
метода в самом низу. Я пытаюсь заставить его возвращать true тогда и только тогда, когда и исходное, и целевое свойство являются любым объектом, который реализует IEnumerable<respectiveTypes>
.
Я пробовал IsAssignableFrom
также IsInstanceOfType
, но, похоже, ни то, ни другое не работает.
Все остальное работает, поскольку, когда я раскомментировал вторую строку метода для явной проверки свойств имени «Дочерние элементы», все работает нормально.
Примечание — я знаю, что с этим примером есть проблемы. А именно, я пытаюсь проверить наличие любого старого, IEnumerable<>
но при этом всегда знаю достаточно, чтобы вернуть List<>
; на данный момент это просто глупое доказательство концепции.
[TestClass]
public class UnitTest1 {
[TestMethod]
public void TestMethod1() {
List<string> strings = new List<string>();
Subject S = new Subject() {
id = 1,
SubjectName = "S1",
Children = { new Subject() { id = 2, SubjectName = "S1a" },
new Subject() { id = 3, SubjectName = "S1b", Children = { new Subject() { id = 4} } } }
};
SubjectViewModel VM = (SubjectViewModel)new SubjectViewModel().InjectFrom<CollectionToCollection>(S); ;
Assert.AreEqual(2, VM.Children.Count);
Assert.AreEqual(1, VM.Children.Single(s => s.id == 3).Children.Count);
}
}
public class Subject {
public Subject() {
Children = new List<Subject>();
}
public string SubjectName { get; set; }
public int id { get; set; }
public List<Subject> Children { get; set; }
}
public class SubjectViewModel {
public SubjectViewModel() {
Children = new List<SubjectViewModel>();
}
public string SubjectName { get; set; }
public int id { get; set; }
public List<SubjectViewModel> Children { get; set; }
}
public class CollectionToCollection : Omu.ValueInjecter.ConventionInjection {
protected override bool Match(ConventionInfo c) {
return c.TargetProp.Name == c.SourceProp.Name;
}
protected override object SetValue(ConventionInfo c) {
if (isCollectionMapping(c))
return (c.SourceProp.Value as IEnumerable<Subject>).Select(s => (SubjectViewModel)(new SubjectViewModel().InjectFrom<CollectionToCollection>(s))).ToList();
else
return c.SourceProp.Value;
}
private bool isCollectionMapping(ConventionInfo c) {
return c.SourceProp.Value.GetType().IsInstanceOfType(typeof(IEnumerable<Subject>)) amp;amp; c.TargetProp.Value.GetType().IsAssignableFrom(typeof(IEnumerable<SubjectViewModel>));
//return c.SourceProp.Name == "Children" amp;amp; c.TargetProp.Name == "Children";
}
}
Ответ №1:
Если у меня есть какой-то объект
o
, как бы я проверил, имеет лиo
какой-то тип, который реализуетIEnumerable<string>
?
Так же просто, как:
o is IEnumerable<string>
Кстати, ваш текущий код не работает, потому что он отменяет проверку отношения присваиваемости (как если бы был вызван метод IsAssignableTo
), т. Е. Предполагается, что:
Bar bar = ...
Foo foo = bar
подразумевает:
typeof(Bar).IsAssignableFrom(typeof(Foo)) // wrong
На самом деле фактическое значение заключается в том, что:
typeof(Foo).IsAssignableFrom(typeof(Bar))
А именно, я пытаюсь проверить наличие любого
старыйIEnumerable<>
:
В этом случае вам нужно проверить, реализует ли тип сконструированную версию универсального интерфейса:
o.GetType()
.GetInterfaces()
.Any(t => t.IsGenericType
amp;amp; t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
Комментарии:
1. Будьте осторожны и помните, что строковый тип — IEnumerable
Ответ №2:
Простая версия этого вопроса такова: если у меня есть какой-то объект o, как я могу проверить, принадлежит ли o какому-либо типу, который реализует
IEnumerable<string>
?
Вот так:
object o = whatever;
bool isSequenceOfStrings = o is IEnumerable<string>;
Комментарии:
1. Кажется, мне действительно трудно найти баланс между слишком большим количеством информации и слишком малым. Мне нужно сделать это с отражением. Извини за путаницу, Эрик. 🙂
2. @Adam: Тогда в чем вопрос? Возникает вопрос: «Если у меня есть объект некоторого типа t, как бы я проверил, реализует ли t IEnumerable<string>?» Или вопрос «Если у меня есть объект некоторого типа t, то как мне проверить, является ли t IEnumerable<string>?» Или вопрос «Если у меня есть объект некоторого типа t, то как мне проверить, преобразуется ли T в IEnumerable<string??» или «… равно IEnumerable<T> для любого T?» или… Это все разные вопросы. Вы получите желаемый ответ, когда зададите вопрос, который вас действительно интересует .
3. Почему вам нужно делать это с отражением?
4. Когда я смотрю на пример кода, я вижу, что вы тестируете c.SourceProp.Value на соответствие реализации буквального интерфейса (IEnumerable<Subject>). Похоже, это не требует отражения. c.SourceProp.Value — IEnumerable<Subject> возвращает тот же результат, не так ли?
5. @Adam: Глядя на ваш код, я не понимаю, почему вы считаете, что вам нужно использовать reflection. Что не так с «(c.SourceProp.Value — IEnumerable<Subject>) amp;amp; (c.TargetProp.Value — IEnumerable<SubjectViewModel>)»???
Ответ №3:
Возможно, я что-то пропустил (не прочитал весь ваш пример кода), но, похоже, вам здесь не нужно отражение.
Как насчет того, чтобы просто использовать:
if (c.SourceProp.Value is IEnumerable<Subject>)
return true;
Если вы не знаете конкретный тип, используйте generics:
public bool MyFunction<T>(...)
{
if (c.SourceProp.Value is IEnumerable<T>)
return true;
}
Или, если вам нужно использовать интерфейс, сделайте это таким образом (сохраните приведение):
var enumerable = c.SourceProp.Value as IEnumerable<string>;
if (enumerable != null)
{
// Use IEnumerable<string>
return true;
}
return false;
Комментарии:
1. Спасибо, да, простое is сработало бы. Не уверен, как я это пропустил. 1