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

本文关键字:泛型 继承 | 更新日期: 2023-09-27 18:27:40

我很难找到正确的方法:

我的数据结构:

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。

我怎样才能强制使用孩子的财产?谢谢

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

您需要使Fluent中的集合通用,以便从中继承的类可以指定类型:

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,因此不需要通过引用传递它。它已经是一个类,所以它本身就是一个引用;调用方将观察到引用对象的突变。

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

例如:

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