如何为2个集合使用相同的foreach代码?

时间:2013-01-26 05:08:55

标签: c# entity-framework

我有两个不同类型的2个集合,但几乎有相同的字段集。 在一个函数中,我需要根据一个条件迭代其中一个集合。 我想只编写一个代码块来覆盖这两种情况。 例: 我有以下代码:

if (condition1)
{
    foreach(var type1var in Type1Collection)
    {

    // Do some code here
       type1var.Notes = "note";
       type1var.Price = 1;
    }
}
else
{
    foreach(var type2var in Type2Collection)
    {

    // the same code logic is used here
       type2var.Notes = "note";        
       type2var.Price = 1;
    }
}

现在:我想简化这段代码只使用相同的逻辑一次(因为它们是相同的),如下所示(PS:我知道下面的代码不正确,我只是解释我想做什么):

var typecollection = Condition1 ? Type1Collection : Type2Collection;

foreach(var typevar in TypeCollection)
{

   // the same code logic is used here
   typevar.Notes = "note";
   typevar.Price = 1;       
 }

Type1&的定义Type2类似于以下代码(实际上它们是实体对象):

    public class Type1 : EntityObject
    {
        public int Type1ID { get; set; }
        public int Type1MasterID { get; set; }

        public String Notes { get; set; }
        public decimal Price { get; set; }
    }

    public class Type2 : EntityObject
    {
        public int Type2ID { get; set; }
        public int Type2MasterID { get; set; }

        public String Notes { get; set; }
        public decimal Price { get; set; }
    }

更新1:

我在foreach块中包含了一些示例代码(我正在访问这两种类型的公共属性)。

更新2:

我已经包含了样本Type1& Type2定义,你可以看到我在两个类中有2个常见的公共属性,我想在foreach块中更新。

更新3:

我很抱歉这种混乱,Type1& Type2派生自EntityObject(它们都是我的实体模型的一部分,Type1Collection& Type2Collection实际上是这两个实体的EntityCollection。

6 个答案:

答案 0 :(得分:9)

你可以使用动态。请注意,您将失去类型安全性。

var list1 = new List<bool>(){true,false};
var list2 = new List<int>(){1,2};

var typecollection = condition1 ? list1.Cast<dynamic>() : list2.Cast<dynamic>();
foreach (var value in typecollection)
{
    //then you can call a method you know they both have
    Debug.WriteLine(value.ToString());
}

或者如果他们共享一个共同的界面,你可以直接投射到那个界面。您将保持类型安全

var list1 = new List<bool>(){true,false};
var list2 = new List<int>(){1,2};

var typecollection = condition1 ? list1.Cast<IConvertible>() : list2.Cast<IConvertible>();
foreach (IConvertible convertible in typecollection)
{
    //we now know they have a common interface so we can call a common method
    Debug.WriteLine(convertible.ToString());
}

答案 1 :(得分:2)

鉴于Jon Skeet提示使用LINQ的Concat方法以及OP声明所涉及的类是EntityObject s,这是另一种可能的解决方案。这假定EntityObject子类定义为部分类:

public partial class Type1 : EntityObject
{
    public int Type1ID { get; set; }
    public int Type1MasterID { get; set; }
    public String Notes { get; set; }
    public decimal Price { get; set; }
}

public partial class Type2 : EntityObject
{
    public int Type2ID { get; set; }
    public int Type2MasterID { get; set; }

    public String Notes { get; set; }
    public decimal Price { get; set; }
}

这允许OP声明具有公共属性的接口,并让他的EntityObject子类实现该接口:

public interface IMyType
{
    String Notes { get; set; }
    decimal Price { get; set; }
}
public partial class Type1 : IMyType {}
public partial class Type2 : IMyType {}

原始代码变为:

var query = (
    from type1var in type1Collection
    where condition1
    select (IMyType)type1var
   ).Concat(
    from type2var in type2Collection
    where !condition1
    select (IMyType)type2var
   );
foreach(var myType in query)
{
    myType.Notes = "note";
    myType.Price = 1;
}

答案 2 :(得分:0)

您可以使用存储在词典中的谓词和动作来完成此操作。我在这里建议动作,因为代码片段似乎没有返回任何内容

public class IterationExample
{
    private readonly Dictionary<bool, Action> dictionary;

    public IterationExample()
    {
        dictionary = new Dictionary<bool, Action> { { true, CollectionOneIterator }, { false, CollectionTwoIterator } };
    }

    public void PublicMethod()
    {
        dictionary[condition]();
    }

    private void CollectionOneIterator()
    {
        foreach (var loopVariable in Type1Collection)
        {
            //Your code here
        }
    }

    private void CollectionTwoIterator()
    {
        foreach (var loopVariable in Type2Collection)
        {
            //Your code here
        }

    }
}

通过这种方式,您的代码的可读性和可测试性得到改善,并且避免了长时间的方法。

编辑:

public class Entity
{
    public IList<string> Type1Collection { get; set; }
    public IList<string> Type2Collection { get; set; } 
}

public class ConsumingClass
{
    public void Example()
    {
        var entity = new Entity();
        entity.PublicMethod();
    }
}

public static class IterationExample
{
    private static readonly Dictionary<bool, Action<Entity>> dictionary;

    static IterationExample()
    {
        dictionary = new Dictionary<bool, Action<Entity>> { { true, CollectionOneIterator }, { false, CollectionTwoIterator } };
    }

    public static void PublicMethod(this Entity entity)
    {
        dictionary[condition]();
    }

    private static void CollectionOneIterator(Entity entity)
    {
        foreach (var loopVariable in entity.Type1Collection)
        {
            //Your code here
        }
    }

    private static void CollectionTwoIterator(Entity entity)
    {
        foreach (var loopVariable in entity.Type2Collection)
        {
            //Your code here
        }
    }
}

答案 3 :(得分:0)

您可以为type1和type2创建一个基类型,用于对两个类之间的公共属性进行分组:

class MyBaseType {
   // Common properties
}

class Type1 : MyBaseType {
   // Specific properties
}

class Type2 : MyBaseType {
   // Specific properties
}

然后,你可以这样做:

IEnumerable<MyBaseType> collection;
if(condition1)
   collection = type1Collection;
else
   collection = type2Collection;

foreach(MyBaseType element in collection) {
   // Common logic
}

编辑: 正如Simon在评论中指出的那样,如果足够的话,你应该使用接口而不是基类型(即你不需要两种类型的特定实现)。

答案 4 :(得分:0)

这不是一个非常好的方法,但它至少可以工作。

        var type1Collection = new Collection<Type1>();
        var type2Collection = new Collection<Type2>();

        var condition1 = new Random().Next(0, 2) != 0;

        dynamic selectedCollection;
        if (condition1)
            selectedCollection = type1Collection;
        else
            selectedCollection = type2Collection;

        foreach (var typeVar in selectedCollection)
        {
            typeVar.Notes = "note";
            typeVar.Price = 1;
        }

答案 5 :(得分:0)

我很惊讶其他人没有建议使用扩展方法:

public interface IMyType
{
    String Notes { get; set; }
    decimal Price { get; set; }
}

public static class MyTypeExtensions
{
    public static void MyLogic(this IMyType myType)
    {
        // whatever other logic is needed
        myType.Notes = "notes";
        myType.Price = 1;
    }
 }

现在,您的原始类型只需要实现IMyType

public class Type1 : IMyType
{
    public int Type1ID { get; set; }
    public int Type1MasterID { get; set; }

    public String Notes { get; set; }
    public decimal Price { get; set; }
}

public class Type2 : IMyType
{
    public int Type2ID { get; set; }
    public int Type2MasterID { get; set; }

    public String Notes { get; set; }
    public decimal Price { get; set; }
}

然后原始代码变为:

if (condition1)
{
    foreach (var type1 in type1Collection)
    {
        type1.MyLogic();
    }
}
else
{
    foreach (var type2 in type2Collection)
    {
        type2.MyLogic();
    }
}