在属性上实现IEnumerable

时间:2010-10-18 17:20:40

标签: c# ienumerable

假设班级

public class Foo 
{
    public List<Bar> Bar = new List<Bar>();
    public string Something;
    public TStatus Status;
}

Bar是一个定义为

的类
public class Bar
{
    public string Code;
    public string Message;
    public TStatus Status;
}

我需要迭代列表栏但我不能使用foreach因为我需要实现IEnumerable我有点新手并且我很难解决如何实现它,任何帮助表示赞赏。

8 个答案:

答案 0 :(得分:11)

有几件事:

1。)至于您的实际问题,您有两种选择:

您可以在代码中迭代Bar字段(或属性,如果您将其更改为属性,如下所述):

Foo foo = new Foo();

foreach(Bar bar in foo.Bar)
{
    ...
}

或者您可以Foo实施IEnumerable<Bar>(这更复杂):

public class Foo : IEnumerable<Bar>
{
    .. your existing code goes here

    public IEnumerator<Bar> GetEnumerator()
    {
        return Bar.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return Bar.GetEnumerator();
    }
}

这将允许您这样做:

Foo foo = new Foo();

foreach(Bar bar in foo)
{

}

就个人而言,我会推荐第一个选项。它更简单,除非Foo真的 (而不仅仅是拥有Bar个对象的集合,否则它看起来更直观。< / p>

2。)上面的内容不是属性,而是公共字段。属性有getter和setter,看起来像这样:

public class Foo
{
    public string Something
    {
        get { return ...; }
        set { ... = value; }
    }
}

属性通常对单个变量进行操作,称为后备存储。对于上述属性,如下所示:

public class Foo
{
    private string something;

    public string Something
    {
        get 
        { 
            return something; 
        }
        set  
        { 
            something = value; 
        }
    }
}

严格地说,您可以放置​​在get块中返回字符串的任何代码块,并且您可以在set块中放置任何内容(包括任何内容,但这不是好主意)。

属性允许您定义行为类似于字段的内容(因为您可以使用等号分配它),但使用您在检索或设置其值时指定的行为。但是,具有非常简单属性的问题之一(只是直接获取/设置后备变量而没有任何其他逻辑)是它实际上做的有点冗长。这就是为什么C#3.0引入了自动属性的概念,如下所示:

public class Foo
{
    public string Something { get; set; }
}

在这里,Something 看起来像某个字段,但它实际上是一个属性。 C#编译器识别此语法(仅用分号替换getset的代码块)并为您创建一个后备变量,并插入代码以从中读取并写入。< / p>

答案 1 :(得分:2)

你可以这样做:

var foo = new Foo();
foo.Bar.Add(new Bar {Code = "code1" });
foo.Bar.Add(new Bar {Code = "code2" });

foreach(var b in foo.Bar)
{
     Console.WriteLine(b.Code);
}

答案 2 :(得分:2)

顺便说一句,如果您希望这些属性为属性,请将字段设为私有,因此:

private List<Bar> _bar = new List<Bar>();


public IEnumerable<Bar> Bar 
{
    get { return _bar; }
}

在更多情况下保持可维护性。

答案 3 :(得分:1)

您应该可以使用Bar轻松地遍历foreach的成员。您无需在此处实施IEnumerable,因为List<>已经为您执行此操作:

var fooInstance = new Foo();
// initialize...
fooInstance.Bar.Add(new Bar {Code = "a" });
fooInstance.Bar.Add(new Bar {Code = "b" });

// iterate over members of Foo.Bar
foreach( var item in fooInstance.Bar )
{
    // access the proeprties of Bar...
    Console.WriteLine( item.Code );
}  

答案 4 :(得分:1)

您可以按原样迭代List<T>

此外 - 您应该使用属性或自动属性来公开List<T>等。公共字段是不好的做法。

类别:

public class Foo 
{
    private List<Bar> _barList;

    public List<Bar> BarList 
    {
        get
        {
            return this._barList ?? (this._barList = new List<Bar>());
        }
    }
}

迭代:

Foo myFoo = new Foo();

myFoo.BarList.Add(new Bar());
myFoo.BarList.Add(new Bar());

foreach(Bar bar in myFoo.BarList)
{
    //do something with bar
}

答案 5 :(得分:1)

猜猜你想这样做:

var enumerator = foo.Bar.GetEnumerator();
while (enumerator.MoveNext())
{
    Console.WriteLine(enumerator.Current);
}

答案 6 :(得分:1)

我会在这里做一个飞跃,你要做的是在你的Foo类中添加一个返回IEnumerableIEnumerable<Bar>并且此属性需要的属性对Bar字段中包含的Foo.Bar个对象列表执行某种过滤。

编辑:如果这听起来不像你想要做的那样,那么这个答案可能不适合你。请不要让我的回答让你进一步混淆。

以下是我对此问题的假设:

  1. FooBar都是另一个类中的嵌套类,而TStatus是包含该类的通用参数。
  2. 您想要向Foo添加一个属性,该属性返回Bar个对象的集合,这些对象的Status属性等于Foo对象的Status属性。我在这里猜测,但我认为这可能就是StatusFooBar属性的原因。
  3. 以下是一个完整的实现,它在BarsFilteredByStatus类上提供Foo属性。这使用.NET iterator functionality提供了Bar对象的过滤集合,其中Bar.Status等于Foo.Status。如果这看起来像你所追求的那样,那就继续吧,拿这个代码来玩吧。

    // an example status enum
    enum SomeStatus
    {
        Open,
        Closed,
        Funky,
    }
    
    // Blarg<TStatus> is just some container class.  This isn't necessary, but it allows TStatus to be a generic parameter rather than a specific type.
    class Blarg<TStatus>
    {
        public class Bar
        {
            public string Code;
            public string Message;
            public TStatus Status;
        }
    
        public class Foo
        {
            public List<Bar> Bar = new List<Bar>();
            public string Something;
            public TStatus Status;
    
            public IEnumerable<Bar> BarsFilteredByStatus
            {
                get
                {
                    // return a filtered collection of bars where Bar.Status equals Foo.Status
                    foreach (var bar in this.Bar)
                    {
                        if (this.Status.Equals(bar.Status))
                            yield return bar;
                    }
                }
            }
        }
    }
    
    // Code from this point on is a usage example
    
    class Program
    {
        static void Main(string[] args)
        {
            // set up some example data
            var bars = new List<Blarg<SomeStatus>.Bar>();
            bars.Add(new Blarg<SomeStatus>.Bar { Code = "123", Status = SomeStatus.Open });
            bars.Add(new Blarg<SomeStatus>.Bar { Code = "234", Status = SomeStatus.Closed });
            bars.Add(new Blarg<SomeStatus>.Bar { Code = "345", Status = SomeStatus.Funky });
            bars.Add(new Blarg<SomeStatus>.Bar { Code = "456", Status = SomeStatus.Open });
            bars.Add(new Blarg<SomeStatus>.Bar { Code = "567", Status = SomeStatus.Funky });
    
            // create a Foo object
            Blarg<SomeStatus>.Foo foo = new Blarg<SomeStatus>.Foo
            {
                Bar = bars,
                Status = SomeStatus.Open,
            };
    
            // now iterate over the Foo.BarsFilteredByStatus property
            // This will iterate over all Bar objects contained within Foo.Bar where Bar.Status equals Foo.Status
            foreach (var bar in foo.BarsFilteredByStatus)
            {
                Console.WriteLine(bar.Code);
            }
        }
    }
    

答案 7 :(得分:0)

以下代码适用于我:

List<Bar> bars = new List<Bar>( );
foreach ( Bar bar in bars ) {
    //Put your code here
}

您应该将List的实例命名为Bar以外的其他实例以避免混淆。