Skip to content

Commit 05545df

Browse files
committed
Migrated final classes which work for .NET Standard 1.6 from FCL extension library.
1 parent 410f1d6 commit 05545df

File tree

13 files changed

+766
-0
lines changed

13 files changed

+766
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using System;
2+
using System.Linq;
3+
using Whathecode.System.Collections.Generic;
4+
using Whathecode.System.Operators;
5+
6+
7+
namespace Whathecode.System.Arithmetic
8+
{
9+
/// <summary>
10+
/// Class which allows to calculate the rate of change of a certain value over a certain interval. (E.g., velocity)
11+
/// </summary>
12+
/// <typeparam name = "TValue">The type of the value for which the rate of change is calculated.</typeparam>
13+
/// <typeparam name = "TOver">The type of the dimension of the interval over which the rate of change is calculated.</typeparam>
14+
public class RateOfChange<TValue, TOver>
15+
where TOver : IComparable<TOver>
16+
{
17+
/// <summary>
18+
/// The interval over which the rate of change should be calculated.
19+
/// </summary>
20+
public TOver Interval { get; private set; }
21+
22+
readonly TupleList<TValue, TOver> _samples = new TupleList<TValue, TOver>();
23+
24+
25+
/// <summary>
26+
/// Create a new instance which allows calculating the rate of change.
27+
/// </summary>
28+
/// <param name = "interval">The interval over which the rate of change should be calculated.</param>
29+
public RateOfChange( TOver interval )
30+
{
31+
Interval = interval;
32+
}
33+
34+
35+
/// <summary>
36+
/// Add a new sample of a value at a given position.
37+
/// </summary>
38+
/// <param name = "sample">The value.</param>
39+
/// <param name = "at">The position of the value.</param>
40+
public void AddSample( TValue sample, TOver at )
41+
{
42+
if ( _samples.Count > 0 && at.CompareTo( _samples.Last().Item2 ) < 0 )
43+
{
44+
throw new ArgumentException( "Samples are required to be added in order.", "at" );
45+
}
46+
47+
_samples.Add( sample, at );
48+
49+
// Clean up samples older than the specified interval.
50+
// TODO: This LINQ query probably isn't optimized for lists. What's the performance impact?
51+
if ( _samples.Count > 2 )
52+
{
53+
var toRemove = _samples
54+
.Reverse<Tuple<TValue, TOver>>()
55+
.Skip( 2 )
56+
.SkipWhile( s => Operator<TOver>.Subtract( at, s.Item2 ).CompareTo( Interval ) <= 0 )
57+
.ToList();
58+
toRemove.ForEach( r => _samples.Remove( r ) );
59+
}
60+
}
61+
62+
/// <summary>
63+
/// Calculate the rate of change based on the samples currently added.
64+
/// </summary>
65+
/// <returns>
66+
/// The rate of change of the passed values, calculated over the indicated interval.
67+
/// If no samples are available, the rate of change is considered to be 0.
68+
/// </returns>
69+
public TValue GetCurrentRateOfChange()
70+
{
71+
if ( _samples.Count == 0 )
72+
{
73+
return CastOperator<double, TValue>.Cast( 0 );
74+
}
75+
76+
Tuple<TValue, TOver> first = _samples.First();
77+
Tuple<TValue, TOver> last = _samples.Last();
78+
79+
double valueDiff = CastOperator<TValue, double>.Cast( Operator<TValue>.Subtract( last.Item1, first.Item1 ) );
80+
double overDiff = CastOperator<TOver, double>.Cast( Operator<TOver>.Subtract( last.Item2, first.Item2 ) );
81+
82+
return CastOperator<double, TValue>.Cast( valueDiff / overDiff );
83+
}
84+
}
85+
}

src/Whathecode.System/EnumHelper.cs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
using Whathecode.System.Reflection.Extensions;
6+
7+
8+
namespace Whathecode.System
9+
{
10+
/// <summary>
11+
/// A generic helper class to do common <see cref="Enum">Enum</see> operations.
12+
/// </summary>
13+
/// <typeparam name = "T">The type of the enum.</typeparam>
14+
public static class EnumHelper<T>
15+
{
16+
/// <summary>
17+
/// Converts the string representation of the name or numeric value of one or more enumerated constants (seperated by comma)
18+
/// to an equivalent enumerated object. A parameter specifies whether the operation is case-sensitive.
19+
/// </summary>
20+
/// <param name = "value">A string containing the name or value to convert.</param>
21+
/// <param name = "ignoreCase">True to ignore case; false to regard case.</param>
22+
public static T Parse( string value, bool ignoreCase = false )
23+
{
24+
return (T)Enum.Parse( typeof( T ), value, ignoreCase );
25+
}
26+
27+
/// <summary>
28+
/// Retrieves an enumerator of the constants in a specified enumeration.
29+
/// </summary>
30+
/// <returns>Enumerable which can be used to enumerate over all constants in the specified enumeration.</returns>
31+
public static IEnumerable<T> GetValues()
32+
{
33+
return from object value in Enum.GetValues( typeof( T ) )
34+
select (T)value;
35+
}
36+
37+
/// <summary>
38+
/// Retrieves an enumerator of all the flagged values in a flags enum.
39+
/// </summary>
40+
/// <param name = "flags">The value specifying the flags.</param>
41+
/// <returns>Enumerable which can be used to enumerate over all flagged values of the passed enum value.</returns>
42+
public static IEnumerable<T> GetFlaggedValues( T flags )
43+
{
44+
if ( !typeof( T ).GetTypeInfo().IsFlagsEnum() )
45+
{
46+
throw new ArgumentException( "The passed enum is not a flags enum.", nameof( flags ) );
47+
}
48+
if ( flags == null )
49+
{
50+
throw new ArgumentNullException( nameof( flags ) );
51+
}
52+
53+
// ReSharper disable PossibleNullReferenceException
54+
return from Enum value in Enum.GetValues( typeof( T ) )
55+
where (flags as Enum).HasFlag( value )
56+
select (T)(object)value;
57+
// ReSharper restore PossibleNullReferenceException
58+
}
59+
60+
/// <summary>
61+
/// Converts an enum of one type to an enum of another type, using a mapping between both.
62+
/// TODO: Support flags enums?
63+
/// </summary>
64+
/// <typeparam name = "TTargetEnum">The target enum type.</typeparam>
65+
/// <param name = "value">The value to map to the other enum type.</param>
66+
/// <param name = "conversionMapping">Dictionary which is used to map values from one enum type to the other.</param>
67+
/// <returns>The passed value, mapped to the desired target enum type.</returns>
68+
public static TTargetEnum Convert<TTargetEnum>( T value, IDictionary<T, TTargetEnum> conversionMapping )
69+
{
70+
if ( !typeof( T ).GetTypeInfo().IsEnum || !typeof( TTargetEnum ).GetTypeInfo().IsEnum )
71+
{
72+
throw new ArgumentException( "The passed value and target type should be enum types." );
73+
}
74+
75+
// ReSharper disable PossibleNullReferenceException
76+
// ReSharper disable AssignNullToNotNullAttribute
77+
return conversionMapping.First( pair => (value as Enum).HasFlag( pair.Key as Enum ) ).Value;
78+
// ReSharper restore AssignNullToNotNullAttribute
79+
// ReSharper restore PossibleNullReferenceException
80+
}
81+
}
82+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
using System.IO;
3+
using System.Linq;
4+
using System.Text.RegularExpressions;
5+
6+
7+
namespace Whathecode.System.IO
8+
{
9+
/// <summary>
10+
/// A helper class for <see cref="Path" /> operations.
11+
/// </summary>
12+
public static class PathHelper
13+
{
14+
/// <summary>
15+
/// Replaces all invalid characters in a given path with a specified character.
16+
/// </summary>
17+
/// <param name = "path">The path to validate and adjust.</param>
18+
/// <param name = "validChar">The character to replace invalid characters with.</param>
19+
/// <returns>The original passed path, with all invalid characters replaced by the given character.</returns>
20+
/// <exception cref="ArgumentException">Thrown when validChar isn't a valid path character.</exception>
21+
public static string ReplaceInvalidChars( string path, char validChar )
22+
{
23+
// TODO: Separate invalid path chars from invalid filename chars?
24+
var invalidChars = Path.GetInvalidPathChars().Concat( Path.GetInvalidFileNameChars() );
25+
26+
if ( invalidChars.Contains( validChar ) )
27+
{
28+
throw new ArgumentException( "The passed replacement character 'validChar' should be a valid path character." );
29+
}
30+
31+
string charsString = invalidChars.Select( c => c.ToString() ).Aggregate( (a, b) => a + b );
32+
string regexMatchAnyChar = "[" + Regex.Escape( charsString ) + "]";
33+
return Regex.Replace( path, regexMatchAnyChar, validChar.ToString() );
34+
}
35+
}
36+
}

src/Whathecode.System/MathHelper.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
using Whathecode.System.Operators;
3+
4+
5+
namespace Whathecode.System
6+
{
7+
/// <summary>
8+
/// A helper class to do common <see cref="Math" /> operations.
9+
/// </summary>
10+
public static class MathHelper
11+
{
12+
public static double RadiansToDegrees( double radians )
13+
{
14+
return radians * (180 / Math.PI);
15+
}
16+
17+
public static double DegreesToRadians( double degrees )
18+
{
19+
return degrees * (Math.PI / 180);
20+
}
21+
22+
/// <summary>
23+
/// Round a value to the nearest multiple of another value.
24+
/// </summary>
25+
/// <typeparam name = "T">The type of the value.</typeparam>
26+
/// <param name = "value">The value to round to the nearest multiple.</param>
27+
/// <param name = "roundToMultiple">The passed value will be rounded to the nearest multiple of this value.</param>
28+
/// <returns>A multiple of roundToMultiple, nearest to the passed value.</returns>
29+
public static T RoundToNearest<T>( T value, T roundToMultiple )
30+
{
31+
double factor = CastOperator<T, double>.Cast( roundToMultiple );
32+
double result = Math.Round( CastOperator<T, double>.Cast( value ) / factor ) * factor;
33+
return CastOperator<double, T>.Cast( result );
34+
}
35+
}
36+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System;
2+
using System.Linq.Expressions;
3+
using System.Reflection;
4+
5+
6+
namespace Whathecode.System.Reflection.Expressions
7+
{
8+
/// <summary>
9+
/// An expression from which open instance and closed instance getters for fields and properties can be created.
10+
/// </summary>
11+
/// <typeparam name = "T">The type of the field or property.</typeparam>
12+
public class GetterExpression<T>
13+
{
14+
ParameterExpression _instance;
15+
string _memberName;
16+
17+
18+
public GetterExpression( FieldInfo field )
19+
{
20+
_instance = Expression.Parameter( field.DeclaringType );
21+
_memberName = field.Name;
22+
}
23+
24+
public GetterExpression( PropertyInfo property )
25+
{
26+
_instance = Expression.Parameter( property.DeclaringType );
27+
_memberName = property.Name;
28+
}
29+
30+
31+
/// <summary>
32+
/// Creates a delegate of a specified type that retrieves the value of this getter of an instance passed as parameter.
33+
/// </summary>
34+
/// <typeparam name = "TInstance">The type of the instance.</typeparam>
35+
/// <returns>A delegate which can be used to retrieve the value of this getter of a passed instance.</returns>
36+
public Func<TInstance, T> OpenInstance<TInstance>()
37+
{
38+
return Expression.Lambda<Func<TInstance, T>>( Expression.PropertyOrField( _instance, _memberName ), _instance ).Compile();
39+
}
40+
41+
/// <summary>
42+
/// Creates a delegate of a specified type that retrieves the value of this getter of an instance.
43+
/// </summary>
44+
/// <param name ="instance">The instance from which to get the value.</param>
45+
/// <returns>A delegate which can be used to retrieve the value of this getter of the passed instance.</returns>
46+
public Func<T> ClosedOver<TInstance>( TInstance instance )
47+
{
48+
var constantInstance = Expression.Constant( instance );
49+
return Expression.Lambda<Func<T>>( Expression.PropertyOrField( constantInstance, _memberName ) ).Compile();
50+
}
51+
}
52+
}

0 commit comments

Comments
 (0)