8

我有 2 种不同类型的 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 的定义类似如下代码(其实它们是Entity对象):

    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 定义,如您所见,我想在 foreach 块中更新这两个类中的 2 个公共公共属性。

更新 3:

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

4

6 回答 6

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());
}
于 2013-01-26T05:16:49.133 回答
2

鉴于 Jon Skeet 暗示使用 LINQ 的Concat方法和 OP 声明所涉及的类是EntityObjects,这是另一种可能的解决方案。这假设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;
}
于 2013-01-28T16:56:49.387 回答
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
        }
    }
}
于 2013-01-26T05:18:25.270 回答
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
}

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

于 2013-01-26T05:20:24.547 回答
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;
        }
于 2013-01-26T15:47:50.927 回答
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();
    }
}
于 2013-01-26T19:14:57.577 回答