我有两个不同类型的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。
答案 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();
}
}