Подтвердить что ты не робот

LINQ: Как объявить IEnumerable [AnonymousType]?

Это моя функция:

    private IEnumerable<string> SeachItem(int[] ItemIds)
    {
        using (var reader = File.OpenText(Application.StartupPath + @"\temp\A_A.tmp"))
        {
            var myLine = from line in ReadLines(reader)
                         where line.Length > 1
                         let id = int.Parse(line.Split('\t')[1])
                         where ItemIds.Contains(id)
                         let m = Regex.Match(line, @"^\d+\t(\d+)\t.+?\t(item\\[^\t]+\.ddj)")
                         where m.Success == true
                         select new { Text = line, ItemId = id, Path = m.Groups[2].Value };
            return myLine;
        }
    }

Я получаю ошибку компиляции, потому что "myLine" не является IEnumerable [string], и я не знаю, как писать IEnumerable [Anonymous]

"Невозможно неявно преобразовать тип 'System.Collections.Generic.IEnumerable [AnonymousType # 1]' в 'System.Collections.Generic.IEnumerable [string]'"

4b9b3361

Ответ 1

Вы не можете объявить IEnumerable<AnonymousType>, потому что тип не имеет имени (имени) во время сборки. Поэтому, если вы хотите использовать этот тип в объявлении функции, сделайте его обычным типом. Или просто измените свой запрос, чтобы вернуть IENumerable<String> и придерживаться этого типа.

Или верните IEnumerable<KeyValuePair<Int32, String>>, используя следующий оператор select.

select new KeyValuePair<Int32, String>(id, m.Groups[2].Value)

Ответ 2

Подпись метода на SearchItem указывает, что метод возвращает IEnumerable<string>, но анонимный тип, объявленный в вашем запросе LINQ, не имеет типа string. Если вы хотите сохранить одну и ту же подпись метода, вам нужно изменить свой запрос, чтобы выбрать только string s. например.

return myLine.Select(a => a.Text);

Если вы настаиваете на возврате данных, выбранных по вашему запросу, вы можете вернуть IEnumerable<object>, если вы замените инструкцию return на

return myLine.Cast<object>();

Затем вы можете использовать объекты с помощью отражения.

Но действительно, если вы собираетесь использовать анонимный тип вне метода, в котором он объявлен, вы должны определить класс a, если метод возвращает IEnumerable этого класса. Анонимные типы - это удобство, но они подвержены злоупотреблениям.

Ответ 3

Я не обязательно рекомендую это... Это своего рода подрывная система типа, но вы можете это сделать:

1) измените вашу подпись метода, чтобы вернуть IEnumerable (не общий)

2) добавьте cast by example helper:

public static class Extensions{
    public static IEnumerable<T> CastByExample<T>(
            this IEnumerable sequence, 
            T example) where T: class
    {
        foreach (Object o in sequence)
            yield return o as T;
    }
}

3) затем вызовите метод примерно так:

var example = new { Text = "", ItemId = 0, Path = "" };
foreach (var x in SeachItem(ids).CastByExample(example))
{
    // now you can access the properties of x 
    Console.WriteLine("{0},{1},{2}", x.Text, x.ItemId, x.Path);
}

И все готово.

Ключом к этому является тот факт, что если вы создадите анонимный тип с тем же порядком, имена типов и свойств в двух местах, типы будут повторно использоваться. Зная это, вы можете использовать дженерики, чтобы избежать отражения.

Надеюсь, что это поможет Alex

Ответ 4

Ваша функция пытается вернуть IEnumerable <string> , когда оператор LINQ, который вы выполняете, фактически возвращает IEnumerable <T> где T - тип, сгенерированный компиляцией. Анонимные типы не всегда анонимны, поскольку они берут конкретный конкретный тип после компиляции кода.

Анонимные типы, однако, поскольку они являются эфемерными до компиляции, могут использоваться только в пределах области, в которой они созданы. Чтобы поддержать ваши потребности в приведенном вами примере, я бы сказал, что самым простым решением является создание простого объекта, который сохраняет результаты вашего запроса:

public class SearchItemResult
{
    public string Text { get; set; }
    public int ItemId { get; set; }
    public string Path { get; set; }
}

public IEnumerable<SearchItemResult> SearchItem(int[] itemIds)
{
    // ...
    IEnumerable<SearchItemResult> results = from ... select new SearchItemResult { ... }
}

Однако, если ваша конечная цель - не извлекать какой-либо объект, и вас интересует только, скажем, Path..., то вы все равно можете создать IEnumerable <string> :

IEnumerable<string> lines = from ... select m.Groups[2].Value;

Я надеюсь, что это поможет прояснить ваше понимание LINQ, перечислений и анонимных типов.:)

Ответ 5

Следует помнить, что операторы LINQ используют отложенное исполнение. Это означает, что ваш оператор LINQ фактически не выполняется до тех пор, пока вы не перейдете к нему в инструкции foreach или вы вызовете метод .ToList() на myLine.
Для вашего примера попробуйте изменить:

return myLine;

To:

return myLine.ToList();

Ответ 6

Не правильный ответ на вопрос, но я надеюсь, что кто-то найдет его полезным, потому что я сначала добрался до этого вопроса, когда искал ответ на свой.

Я только что нашел один интересный способ объявить анонимный IEnumerable.

//Declaration. The type of newEnumerable is IEnumerable<'a>
var newEnumerable = new string[] { }.Select(x => new {SomeInt = 0, SomeString = ""});

Таким образом, использование этого будет выглядеть так...

//Adding value
newEnumerable = someOtherEnumerable.Select(x => new {x.SomeInt, x.SomeString});

//Adding multiple values via concatanation
someAnotherEnumerable.ForEach(x =>
    {
        newEnumerable = newEnumerable.Concat(new []{
            new {x.SomeInt, x.SomeString}
        });
    });