Проверка на IEnumerable <T>с отражением - PullRequest
14 голосов
/ 06 апреля 2011

РЕДАКТИРОВАТЬ

Базовая версия этого вопроса: если у меня есть object o, как бы я проверил, если o имеет какой-то тип, который реализует IEnumerable<string> с отражением ?Оригинальный вопрос гораздо более конкретен, но ответ на вышесказанное был бы столь же хорош.Извините, если я дал слишком много подробностей по этому вопросу

КОНЕЦ РЕДАКТИРОВАНИЯ

Следующее является надуманным ValueInjecter POC.Все работает хорошо, за исключением метода isCollectionMapping в самом низу.Я пытаюсь заставить его возвращать true, если и только если свойство source и target является любым объектом, который реализует IEnumerable<respectiveTypes>.

Я пробовал IsAssignableFrom, а также IsInstanceOfType, но никажется, работает.

Все остальное работает, так как, когда я раскомментирую вторую строку метода, чтобы явно проверить свойства имени "Children", он работает нормально.

Примечание - Я знаю, что есть проблемы с этим примером.А именно, я пытаюсь проверить любой старый 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>)) && c.TargetProp.Value.GetType().IsAssignableFrom(typeof(IEnumerable<SubjectViewModel>));

        //return c.SourceProp.Name == "Children" && c.TargetProp.Name == "Children";
    }
}

Ответы [ 3 ]

29 голосов
/ 06 апреля 2011

Если бы у меня был какой-то объект 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 
        && t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
10 голосов
/ 06 апреля 2011

Базовая версия этого вопроса: если у меня есть какой-то объект o, как бы я проверил, имеет ли o какой-то тип, реализующий IEnumerable<string>?

Как это:

object o = whatever;
bool isSequenceOfStrings = o is IEnumerable<string>;
5 голосов
/ 06 апреля 2011

Я мог что-то пропустить (не прочитал весь пример кода), но, похоже, вам здесь не нужно размышлять.

Как насчет использования:

if (c.SourceProp.Value is IEnumerable<Subject>)
   return true;

Если вы не знаете конкретный тип, используйте дженерики:

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;
...