[英]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.