Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 对属性执行通用且快速的计算_C#_Loops_Generics_Properties - Fatal编程技术网

C# 对属性执行通用且快速的计算

C# 对属性执行通用且快速的计算,c#,loops,generics,properties,C#,Loops,Generics,Properties,目标是创建一个方法,该方法通常以性能方式对对象列表的属性执行计算。下面是整个测试代码: using System; using System.Collections.Generic; namespace TestApp { public class Minute { public DateTime DateTimeUtc { get; set; } public float Source { get; set; }

目标是创建一个方法,该方法通常以性能方式对对象列表的属性执行计算。下面是整个测试代码:

using System;
using System.Collections.Generic;

namespace TestApp
{
        public class Minute
        {
            public DateTime DateTimeUtc { get; set; }
            public float Source { get; set; }
            public float Mult2 { get; set; }
            public float Mult3 { get; set; }
            public float Mult4 { get; set; }
        }

        class Program
        {
            public static List<Minute> Minutes = new List<Minute>();

            static void Main(string[] args)
            {

                for (int i = 1; i < 10000000; i++)
                {
                    Minute newMinute = new Minute();
                    newMinute.Source = i;
                    Minutes.Add(newMinute);
                }

                GenerateMult2(Minutes, 2); // 160 ms
                GenerateMult2Generic(Minutes, typeof(Minute), nameof(Minute.Source), nameof(Minute.Mult2),2); // 4300 ms
            }

            public static void GenerateMult2(List<Minute> Minutes, int multiplier)
            {
                for (int i = 0; i < Minutes.Count; i++)
                {
                    // Simplified calculation, there will eventually be a lot more code that goes here!
                    Minutes[i].Mult2 = Minutes[i].Source * multiplier;
                }
            }

            public static void GenerateMult2Generic<T>(List<T> SourceList, Type ContainerType, string propNameSource, string propNameMult, int multiplier)
            {
                var propertyInfoSource = ContainerType.GetProperty(propNameSource);
                var propertyInfoMult = ContainerType.GetProperty(propNameMult);

                foreach (T item in SourceList)
                {
                    float sourceValue = (float)propertyInfoSource.GetValue(item);
                    propertyInfoMult.SetValue(item, sourceValue * multiplier);
                }
            }
        }
    }
使用系统;
使用System.Collections.Generic;
命名空间TestApp
{
公开课堂记录
{
公共日期时间日期时间UTC{get;set;}
公共浮点源{get;set;}
公共浮点Mult2{get;set;}
公共浮点Mult3{get;set;}
公共浮点Mult4{get;set;}
}
班级计划
{
公共静态列表分钟数=新列表();
静态void Main(字符串[]参数)
{
对于(int i=1;i<10000000;i++)
{
分钟新分钟=新分钟();
newMinute.Source=i;
分钟。添加(新分钟);
}
GenerateMult2(分钟,2);//160毫秒
GenerateMult2Generic(分钟,类型(分钟),名称(分钟.来源),名称(分钟.Mult2),2);/4300毫秒
}
公共静态void GenerateMult2(列表分钟数,整数倍增)
{
for(int i=0;i
在这个测试应用程序中,有一个名为GenerateMult2的方法,其目的是对微小对象列表中的一个属性进行一些计算。这种方法效果好,速度快。问题是方法太具体了。如果我想对属性Mult3和Mult4进行相同的计算,我需要为每个属性创建一个单独的方法,这是太多重复的代码。我想让这个方法更通用,也就是说,我想这个方法也接受其他类型的列表,例如一个日期对象或第二个对象的列表。此外,我想告诉方法要对哪个属性执行计算

因此,我尝试创建一个名为GenerateMult2Generic的通用方法。此方法执行与GenerateMult2方法完全相同的计算,并且是多用途的,这正是我想要的。最大的缺点是它的方式太慢,由于反射

GenerateMult2方法如何以通用方式生成,但性能损失不超过5%

使用解决方案更新

在研究了这里的答案后,最好的答案是Ed Plunkett给出的,但不知何故被删除了。因此,我发布的原始代码更新了该答案中的想法:

using System;
using System.Collections.Generic;
using System.Linq;

namespace TestApp
{
    public class Minute : BaseTime
    {
        public float MovingAverageFast { get; set; }
        public float MovingAverageSlow { get; set; }
        public float RsiFast { get; set; }
        public float RsiSlow { get; set; }
    }

    public class Day : BaseTime
    {
        public float MovingAverageFast { get; set; }
        public float MovingAverageSlow { get; set; }
        public float RsiFast { get; set; }
        public float RsiSlow { get; set; }
    }

    public class BaseTime
    {
        public DateTime DateTimeUtc { get; set; }
        public float Source { get; set; }
    }

    class Program
    {
        public static List<Minute> Minutes = new List<Minute>();
        public static List<Day> Days = new List<Day>();

        static void Main(string[] args)
        {
            Minutes = Enumerable.Range(1, 10000000).Select(n => new Minute { Source = n }).ToList();
            Days = Enumerable.Range(1, 10000000).Select(n => new Day { Source = n }).ToList();

            // Generating data for Minutes
            GenerateMovingAverage(Minutes, 100, (m, value) => ((Minute)m).MovingAverageFast = value);
            GenerateMovingAverage(Minutes, 500, (m, value) => ((Minute)m).MovingAverageSlow = value);
            GenerateRsi(Minutes, 60, (m, value) => ((Minute)m).RsiFast = value);
            GenerateRsi(Minutes, 250, (m, value) => ((Minute)m).RsiSlow = value);

            // Generating data for Days
            GenerateMovingAverage(Days, 8, (d, value) => ((Day)d).MovingAverageFast = value);
            GenerateMovingAverage(Days, 45, (d, value) => ((Day)d).MovingAverageSlow = value);
            GenerateRsi(Days, 5, (d, value) => ((Day)d).RsiFast = value);
            GenerateRsi(Days, 21, (d, value) => ((Day)d).RsiSlow = value);
        }

        public static void GenerateMovingAverage(IEnumerable<BaseTime> BaseTimeObjects, int Period, Action<BaseTime, float> setter)
        {
            foreach (var BaseTimeObject in BaseTimeObjects)
            {
                float newValue;
                newValue = BaseTimeObject.Source * Period; // pseudo calculation for generating moving average
                setter(BaseTimeObject, newValue);
            }
        }

        public static void GenerateRsi(IEnumerable<BaseTime> BaseTimeObjects, int Period, Action<BaseTime, float> setter)
        {
            foreach (var BaseTimeObject in BaseTimeObjects)
            {
                float newValue;
                newValue = BaseTimeObject.Source / Period; // pseudo calculation for generating rsi
                setter(BaseTimeObject, newValue);
            }
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
命名空间TestApp
{
公开课分钟:基准时间
{
公共浮点移动平均快速{get;set;}
公共浮点移动平均流{get;set;}
公共浮点数{get;set;}
公共浮点数{get;set;}
}
公众上课日:基准时间
{
公共浮点移动平均快速{get;set;}
公共浮点移动平均流{get;set;}
公共浮点数{get;set;}
公共浮点数{get;set;}
}
公共类基时
{
公共日期时间日期时间UTC{get;set;}
公共浮点源{get;set;}
}
班级计划
{
公共静态列表分钟数=新列表();
公共静态列表天数=新列表();
静态void Main(字符串[]参数)
{
Minutes=Enumerable.Range(1100000).Select(n=>newminute{Source=n}).ToList();
Days=Enumerable.Range(1100000).Select(n=>newday{Source=n}).ToList();
//生成分钟数据
生成移动平均值(分钟,100,(米,值)=>(分钟)米。移动平均值=值);
生成平均值(分钟,500,(米,值)=>(分钟)米。移动平均值=值);
生成器i(分钟,60,(米,值)=>((分钟)米)。RsiFast=值);
发电机i(分钟,250,(米,值)=>((分钟)米)。RsiSlow=值);
//生成数天的数据
生成平均值(天,8,(d,值)=>((天)d)。移动平均值=值);
生成平均值(天,45,(d,值)=>((天)d)。移动平均值=值);
发电机指数(天,5,(d,值)=>((天)d)。RsiFast=值);
发电机指数(天,21,(d,值)=>((天)d)。RsiSlow=值);
}
公共静态void GenerateMovingAverage(IEnumerable BaseTimeObjects、int句点、动作设置器)
{
foreach(BaseTimeObjects中的var BaseTimeObject)
{
浮动新值;
newValue=BaseTimeObject.Source*Period;//生成移动平均值的伪计算
setter(BaseTimeObject,newValue);
}
}
公共静态void生成器(IEnumerable BaseTimeObjects、int句点、动作设置器)
{
foreach(BaseTimeObjects中的var BaseTimeObject)
{
浮动新值;
newValue=BaseTimeObject.Source/Pe
interface ITimeMulti
{
    DateTime DateTimeUtc { get; set; }

    float Source { get; set; }

    // will be used for number of available properties.
    int MultCount { get; } 

    // the main method for generating the multipliers. 
    void Generate(int multNumber, int multiplier); 
}
public class TimeMulti : ITimeMulti
{
    public DateTime DateTimeUtc { get; set; }

    public float Source { get; set; }

    // Using Dictionary will be much faster than Reflection 
    protected static Dictionary<string, float> Multipliers { get; set; }

    // Number of Properties (the set should be within the derived classes)
    public int MultCount { get; protected set; }


    // This is a restriction to create this instance from the derived classes only 
    private TimeMulti() { } 

    // for derived classes 
    protected TimeMulti(int multCount)
    {
        // Should be in this constructor only
        Initiate(multCount);
    }

    // This is the main method to generate the multiplication part. 
    public void Generate(int multNumber, int multiplier)
    {
        if (multNumber == 0)
        {
            Multipliers["Mult"] = Source * multiplier;
        }
        else if (Multipliers.ContainsKey("Mult" + multNumber))
        {
            // store the value in the dictionary (this is for reference)
            Multipliers["Mult" + multNumber] = SetMult(multNumber, Source * multiplier);
        }
        else
        {
            throw new NullReferenceException();
        }

    }

    // On new instance, this will fired, which will setup the dictionary
    protected void Initiate(int numberOfMultipliers)
    {
        // Ensure you have an active instance of the dictionary
        if (Multipliers == null)
            Multipliers = new Dictionary<string, float>();

        // Ensurance 
        if(numberOfMultipliers > 0)
        {
            MultCount = numberOfMultipliers;

            for (int x = 1; x <= numberOfMultipliers; x++)
                if (!Multipliers.ContainsKey("Mult" + x))
                    Multipliers.Add("Mult" + x, 0);
        }
        else
        {
            throw new ArgumentOutOfRangeException();
        }

    }

    // this is where we will replace Reflection, here is just returning the multValue
    // we will override it on the derived classes 
    protected virtual float SetMult(int MultNumber, float multValue) => multValue;

}
public class Minute : TimeMulti
{
    public float Mult1 { get; set; }
    public float Mult2 { get; set; }
    public float Mult3 { get; set; }
    public float Mult4 { get; set; }

    // MultCount = 4
    public Minute(): base(4) { }

    // This method will set the value of the property using switch statment, with this, you will avoid Reflection. 
    protected override float SetMult(int multNumber, float multValue)
    {
        switch (multNumber)
        {
            case 1:
                Mult1 = multValue;
                break;
            case 2:
                Mult2 = multValue;
                break;
            case 3:
                Mult3 = multValue;
                break;
            case 4:
                Mult4 = multValue;
                break;
        }

        return multValue;
    }   

}
   class Program
{
    // Create List with type of the ITimeMulti interface
    public static List<ITimeMulti> Minutes = new List<ITimeMulti>();

    static void Main(string[] args)
    {
        // Generate a sample
        for (int i = 1; i < 10000000; i++)
            Minutes.Add(new Minute() { Source = i});

        // Calculate 
        GenerateMultipliers(Minutes, 1, 2); 

    }

    public static void GenerateMultipliers(List<ITimeMulti> source, int multNumber, int multiplier)
    {
        for (int i = 0; i < source.Count; i++)
        {
            source[i].Generate(multNumber, multiplier);
        }

    }

}
   public class Day : TimeMulti
    {
        // Properties 
        public float Mult1 { get; set; }

        // Constructor 
        public Day(): base(1) { }

        // This method to map the values to the properties 
        protected override float SetMult(int multNumber, float multValue)
        {
            switch (multNumber)
            {
                case 1:
                    Mult1 = multValue;
                    break;
            }

            return multValue;
        }   

    }
public class BaseTime
{
    // shared proprties 
    public DateTime DateTimeUtc { get; set; }
    public float Source { get; set; }
    public float MovingAverageFast { get; set; }
    public float MovingAverageSlow { get; set; }
    public float RsiFast { get; set; }
    public float RsiSlow { get; set; }

}

public class Minute : BaseTime
{
    // add your custom code for Minute
    // No need for recreating them, since it's already inherited from the base 
}

public class Day : BaseTime
{
    // add your custom code for Day
    // No need for recreating them, since it's already inherited from the base 
}

class Program
{
    public static BaseTime[] Minutes;

    public static BaseTime[] Days;

    static void Main(string[] args)
    {
        Minutes = Enumerable.Range(1, 10000000).Select(n => (BaseTime) new Minute { Source = n }).ToArray();
        Days = Enumerable.Range(1, 10000000).Select(n => (BaseTime) new Day { Source = n }).ToArray();

        // Generating data for Minutes
        GenerateMovingAverage(Minutes, 100, (m, value) => m.MovingAverageFast = value);
        GenerateRsi(Minutes, 60, (m, value)  => m.RsiFast = value);
        GenerateRsi(Minutes, 250, (m, value) => m.RsiSlow = value);

        // Generating data for Days
        GenerateMovingAverage(Days, 8, (d, value)  => d.MovingAverageFast = value);
        GenerateMovingAverage(Days, 45, (d, value) => d.MovingAverageSlow = value);
        GenerateRsi(Days, 5, (d, value)  => d.RsiFast = value);
        GenerateRsi(Days, 21, (d, value) => d.RsiSlow = value);         
    }

    public static void GenerateMovingAverage(BaseTime[] BaseTimeObjects, int Period, Action<BaseTime, float> setter) 
    {
        foreach (var BaseTimeObject in BaseTimeObjects)
        {
            setter(BaseTimeObject, BaseTimeObject.Source * Period);
        }
    }

    public static void GenerateRsi(BaseTime[] BaseTimeObjects, int Period, Action<BaseTime, float> setter)
    {
        foreach (var BaseTimeObject in BaseTimeObjects)
        {
            setter(BaseTimeObject, BaseTimeObject.Source / Period);
        }
    }

}
public interface IMultiValueGenerator
{
  void GenerateValue(ITimeMulti multi, int multiplier);
}

public class Multi2Generator : IMultiValueGenerator
{
  public void GenerateValue(ITimeMulti multi, int multiplier)
  {
    multi.Mult2 = multi.Source * multiplier;
  }
}

public static class MultiGeneratorFactory
{
   public static IMultiValueGenerator GetGenerator(...)
   {
      if (condition)
        return new Multi2Generator();
      // etc
   }
}