Can anyone tell me if there is a way with generics to limit a generic type argument T
to only:
Int16
Int32
If all you want is use one numeric type, you could consider creating something similar to an alias in C++ with using
.
So instead of having the very generic
T ComputeSomething<T>(T value1, T value2) where T : INumeric { ... }
you could have
using MyNumType = System.Double;
T ComputeSomething<MyNumType>(MyNumType value1, MyNumType value2) { ... }
That might allow you to easily go from double
to int
or others if needed, but you wouldn't be able to use ComputeSomething
with double
and int
in the same program.
But why not replace all double
to int
then? Because your method may want to use a double
whether the input is double
or int
. The alias allows you to know exactly which variable uses the dynamic type.
Workaround using policies:
interface INumericPolicy<T>
{
T Zero();
T Add(T a, T b);
// add more functions here, such as multiplication etc.
}
struct NumericPolicies:
INumericPolicy<int>,
INumericPolicy<long>
// add more INumericPolicy<> for different numeric types.
{
int INumericPolicy<int>.Zero() { return 0; }
long INumericPolicy<long>.Zero() { return 0; }
int INumericPolicy<int>.Add(int a, int b) { return a + b; }
long INumericPolicy<long>.Add(long a, long b) { return a + b; }
// implement all functions from INumericPolicy<> interfaces.
public static NumericPolicies Instance = new NumericPolicies();
}
Algorithms:
static class Algorithms
{
public static T Sum<P, T>(this P p, params T[] a)
where P: INumericPolicy<T>
{
var r = p.Zero();
foreach(var i in a)
{
r = p.Add(r, i);
}
return r;
}
}
Usage:
int i = NumericPolicies.Instance.Sum(1, 2, 3, 4, 5);
long l = NumericPolicies.Instance.Sum(1L, 2, 3, 4, 5);
NumericPolicies.Instance.Sum("www", "") // compile-time error.
The solution is compile-time safe. CityLizard Framework provides compiled version for .NET 4.0. The file is lib/NETFramework4.0/CityLizard.Policy.dll.
It's also available in Nuget: https://www.nuget.org/packages/CityLizard/. See CityLizard.Policy.I structure.
I would use a generic one which you could handle externaly...
/// <summary>
/// Generic object copy of the same type
/// </summary>
/// <typeparam name="T">The type of object to copy</typeparam>
/// <param name="ObjectSource">The source object to copy</param>
public T CopyObject<T>(T ObjectSource)
{
T NewObject = System.Activator.CreateInstance<T>();
foreach (PropertyInfo p in ObjectSource.GetType().GetProperties())
NewObject.GetType().GetProperty(p.Name).SetValue(NewObject, p.GetValue(ObjectSource, null), null);
return NewObject;
}