2009-06-08 6 views
2

В коде ниже, как объявить myLine как общедоступную (глобальную) переменную? Проблема в том, что я не могу использовать ключевое слово «var».Как объявить поле с анонимным типом (C#)

public static IEnumerable<string> ReadLines(StreamReader reader) 
    { 
     while (!reader.EndOfStream) 
     { 
      yield return reader.ReadLine(); 
     } 
    } 

    private void Filter1(string filename) 
    { 
     using(var writer = File.CreateText(Application.StartupPath + "\\temp\\test.txt")) 
     { 
      using (var reader = File.OpenText(filename)) 
      { 
       int[] Ids = { 14652, 14653, 14654, 14655, 14656, 14657, 14658, 14659, 14660 }; 
       var myLine = from line in ReadLines(reader) 
          where line.Length > 1 
          let id = int.Parse(line.Split('\t')[1]) 
          where Ids.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 }; 


       foreach (var id in myLine) 
       { 
        writer.WriteLine("Item Id = " + id.ItemId); 
        writer.WriteLine("Path = " + id.Path); 
        writer.WriteLine("\n"); 
       } 

      } 
     } 
    } 

Я хочу это сделать, потому что мне нужно найти способ получить доступ к этому ienumerable для последующего использования.

+1

http://blogs.msdn.com/ericlippert/archive/2009/01/26/why-no-var-on-fields.aspx –

ответ

8

Проблема в том, что он использует анонимный тип, который нельзя использовать в объявлении поля.

Исправление состоит в том, чтобы написать именованный тип с теми же членами и использовать этот тип в запросе. Если вы хотите иметь такое же поведение, как ваш анонимный тип, он должен:

  • принимать все значения в конструкторе
  • незыблемыми, обнажая свойства только для чтения
  • Override Equals, GetHashCode и ToString
  • быть запечатаны

Вы могли просто использовать отражатель декомпилировать код, но т и вы получите общий тип, который вам действительно не нужен.

Класс будет выглядеть примерно так:

public sealed class Foo 
{ 
    private readonly string text; 
    private readonly int itemId; 
    private readonly string path; 

    public Foo(string text, int itemId, string path) 
    { 
     this.text = text; 
     this.itemId = itemId; 
     this.path = path; 
    } 

    public string Text 
    { 
     get { return text; } 
    } 

    public int ItemId 
    { 
     get { return itemId; } 
    } 

    public string Path 
    { 
     get { return path; } 
    } 

    public override bool Equals(object other) 
    { 
     Foo otherFoo = other as Foo; 
     if (otherFoo == null) 
     { 
      return false; 
     } 
     return EqualityComparer<string>.Default.Equals(text, otherFoo.text) && 
     return EqualityComparer<int>.Default.Equals(itemId, otherFoo.itemId) && 
     return EqualityComparer<string>.Default.Equals(path, otherFoo.path); 
    } 

    public override string ToString() 
    { 
     return string.Format("{{ Text={0}, ItemId={1}, Path={2} }}", 
          text, itemId, path); 
    } 

    public override int GetHashCode() 
    { 
     int hash = 17; 
     hash = hash * 23 + EqualityComparer<string>.Default.GetHashCode(text); 
     hash = hash * 23 + EqualityComparer<int>.Default.GetHashCode(itemId); 
     hash = hash * 23 + EqualityComparer<string>.Default.GetHashCode(path); 
     return hash; 
    } 
} 

Ваш запрос будет просто изменить в конце концов:

select new Foo(line, id, m.Groups[2].Value) 
+0

В основном я делаю экземпляр класса Foo для каждого ItemId, правильно? Еще один вопрос. Если бы я мог спросить вас, почему вы объявляете их частными? Несколько месяцев назад вы научили меня объявлять их публичным текстовым текстом {get; private set}; –

+0

Это объявление * свойства * с публичным получателем и частным сеттером. Здесь у нас есть публичные getters для свойств, * no * setters вообще и частные поля. По возможности, я предпочитаю полностью читать только классы. –

+0

О, я забыл самое главное. Каким будет тип IEnumerable с помощью вашего кода? IEnumerable ? –

2

Вместо того, чтобы использовать анонимный класс с новой клавиатуры, определим класс явно с текстом, ItemId и т. д. Тогда тип будет IQueryable <MyClass>. Используйте это вместо ключевого слова var.