C#继承,新修饰符和泛型

时间:2013-08-13 15:12:41

标签: c# linq generics inheritance name-hiding

我正努力寻找纠正方法:

我的数据结构:

public abstract class Flow
{
    public virtual double Value { get; set; }
    public virtual DateTime Time { get; set; }
}

public class InboundFlow : Flow
{
}

public class OutboundFlow : Flow
{
}

我的业务对象包含这些数据结构的集合

public abstract class Fluent
{
    public virtual IList<Flow> FlowCollection { get; set; }
    public virtual double InitialBaseflow { get; set; }
}

public class Affluent : Fluent
{
    public new virtual IList<InboundFlow> FlowCollection { get; set; }
}

public class Effluent : Fluent
{
    public new virtual IList<OutboundFlow> FlowCollection { get; set; }
}

我正在尝试使用的通用方法:

private static void FindInitialBaseflow<T>(ref T fluent) where T : Fluent
    {
        var linqFluent = fluent;

        var flows = linqFluent.FlowCollection.ToList().FindAll(
                    flow =>
                    flow.Time >= SOME_DATE &&
                    flow.Time < SOME_OTHER_DATE);
        var initialBaseflow = flows.Average(flow => flow.Value);
        fluent.InitialBaseflow = Math.Round(initialBaseflow, 5);  
    }

我的问题是在linq方法中调用“linqfluent.FlowCollection”会调用基类Fluent的FlowCollection ,它是null。

如何强制使用孩子的财产呢?谢谢!

2 个答案:

答案 0 :(得分:1)

您需要在Fluent generic中创建集合,以便从中继承的类可以指定类型:

public class Fluent<T>
    where T : Flow
{
    public IList<T> FlowCollection { get; set; }
    public double InitialBaseflow { get; set; }
}

一旦你有了这个,你甚至不需要Flow的子类,你可以把它变得具体。

您可以轻松修改它的使用以适应此模型:

private static void FindInitialBaseflow<T>(Fluent<T> fluent) 
    where T : Flow
{
    var linqFluent = fluent;

    var flows = linqFluent.FlowCollection.Where(
                flow =>
                flow.Time >= SOME_DATE &&
                flow.Time < SOME_OTHER_DATE);
    var initialBaseflow = flows.Average(flow => flow.Value);
    fluent.InitialBaseflow = Math.Round(initialBaseflow, 5);
}

另请注意,由于您未在此方法中设置fluent,因此无需通过引用传递它。它已经是一个类了,所以 本身就是一个引用;调用者将观察引用对象的突变。

答案 1 :(得分:-1)

泛型是错误的工具。您应该使用多态来确保根据类型调用正确的实现。

例如:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace ConsoleApp
{
    public abstract class Flow
    {
        public virtual double Value { get { return new Random().Next() ; } }//these values are just for demonstration purposes
        public virtual DateTime Time
        {
            get
            {
                return DateTime.MinValue.AddYears(1);
            }
        }
    }

    public class InboundFlow : Flow
    {
    }

    public class OutboundFlow : Flow
    {
    }

    public abstract class Fluent
    {
        IList<Flow> _flowCollection;
        public virtual IList<Flow> FlowCollection
        {
            get { return _flowCollection; }
            set { _flowCollection = value; }
        }

        private double _initialBaseflow;
        public virtual double InitialBaseflow
        {
            get { return _initialBaseflow; }
            set { _initialBaseflow = value; }
        }

        public Fluent()
        {
            FlowCollection = new List<Flow>();
        }
    }

    public class Affluent : Fluent
    {
        //public new virtual IList<InboundFlow> FlowCollection { get; set; }//Keep the property polymorphic

        public Affluent()
        {
            FlowCollection = new List<Flow>();
        }
    }

    public class Effluent : Fluent
    {
        //public new virtual IList<OutboundFlow> FlowCollection { get; set; }

        public Effluent()
        {
            FlowCollection = new List<Flow>();
        }
    }

    class Program
    {
        public static DateTime SOME_DATE { get { return DateTime.MinValue; } }
        public static DateTime SOME_OTHER_DATE { get { return DateTime.Now; } }

        static void Main(string[] args)
        {
            var inbound = new InboundFlow();
            var inbound2 = new InboundFlow();
            var outbound = new OutboundFlow();
            var a = new Affluent();            
            a.FlowCollection.Add(inbound);
            a.FlowCollection.Add(inbound2);
            FindInitialBaseflow(a);
        }

        private static void FindInitialBaseflow(Fluent fluent)
        {
            var linqFluent = fluent;

            var flows = linqFluent.FlowCollection.ToList().FindAll(
                        flow =>
                        flow.Time >= SOME_DATE &&
                        flow.Time < SOME_OTHER_DATE);
            var initialBaseflow = flows.Average(flow => flow.Value);
            fluent.InitialBaseflow = Math.Round(initialBaseflow, 5);
        }
    }
}