簡體   English   中英

如何為2個集合使用相同的foreach代碼?

[英]How to use the same foreach code for 2 collections?

我有兩個不同類型的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。

你可以使用動態。 請注意,您將失去類型安全。

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());
}

鑒於Jon Skeet使用LINQ的Concat方法和OP聲明所涉及的類是EntityObject的說法,這是另一種可能的解決方案。 這假設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;
}

您可以使用存儲在詞典中的謂詞和動作來完成此操作。 我在這里建議動作,因為代碼片段似乎沒有返回任何內容

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
        }
    }
}

您可以為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在評論中指出的那樣,如果足夠的話,你應該使用一個接口而不是一個基本類型(即你不需要兩種類型的特定實現)。

這不是一個非常好的方法,但它至少是工作。

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

我很驚訝其他人沒有建議使用擴展方法:

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();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM