Click to See Complete Forum and Search --> : Casting int/double to generics?


THY02K
January 24th, 2009, 10:26 PM
I was having problem (see below "TROUBLE") casting int/double to generics ... This is what I intended to write,
public T RecursiveGetNextRandom<T>(T Max, T Min, List<T> lstExcludedNum)
{
int nNextNum = 0;
double dbNextNum 0;
T NextNum;

nMin = Convert.ToInt32(Min);
nMax = Convert.ToInt32(Max);
nNextNum = oRand.Next(nMin, nMax);
if(Max is double)
{
dbNextNum = oRand.NextDouble() * nNextNum;
NextNum = (T) dbNextNum; << TROUBLE: Can't cast to <T>!
} else if (Max is int) {
NextNum = (T) nNextNum; << TROUBLE: Can't cast to <T>!
}

return NextNum;
}

I ended up writing the following ugly code:
public static object RecursiveGetNextRandom(object Max, object Min, ArrayList lstExcludedNum)
{
object NextNum = 0;
Random oRand = new Random(Guid.NewGuid().GetHashCode());
double dbMin;
double dbMax;
int nNextNum;

if (Min == null)
{
Min = Int32.MinValue;
}

if (Max == null)
{
Max = Int32.MaxValue;
}

if (!(Max is int || Max is double))
{
...
}

dbMin = Convert.ToInt32(Min);
dbMax = Convert.ToInt32(Max);
SwapIfGreater(ref dbMin, ref dbMax);
nNextNum = oRand.Next(Convert.ToInt32(Math.Floor(dbMin)), Convert.ToInt32(Math.Floor(dbMax)));

if (Max is double)
{
NextNum = (double)nNextNum * oRand.NextDouble();
}
else if (Max is int)
{
NextNum = (int)nNextNum;
}

if (lstExcludedNum != null)
{
if (lstExcludedNum.Contains(NextNum))
{
RecursiveGetNextRandom(Max, Min, lstExcludedNum);
}
}

return NextNum;
}


Any suggestion? Thanks!~

Arjay
January 24th, 2009, 11:01 PM
How about make two different [static] method overloads?

public int RecursiveGetNextRandom(int max, int min, List<int> lstExcludedNum);

public double RecursiveGetNextRandom(double max, double min, List<double> lstExcludedNum);

toraj58
January 25th, 2009, 07:28 AM
you can use generics in an ugly way like this:


class Program
{
static void Main(string[] args)
{

Program prg = new Program();
test<Program>(prg);
}

static protected void test<T>(T str)
{
string str1 = str.ToString();
Console.WriteLine(str1);

//int x = 123;
//T y = (T)x;

Console.ReadKey(true);
}
}


how do you expect that compiler guess what cast you will do after initializing the generic and in this examle (that works fine) how do you expect that you cast an int to Program type.

uncomment the commented lines then you will see that you get compile-time error that is good becaue it prevents run-time errors.

darwen
January 25th, 2009, 11:35 AM
Have you thought about using the Convert class ?


class RangedRandom<T>
where T : IConvertible
{
private Random _random = new Random();
private double _min;
private double _range;
private static readonly Type ElementType = typeof(T);

public RangedRandom(T min, T max)
{
_min = Convert.ToDouble(min);
_range = Convert.ToDouble(max) - _min;
}

public T Next()
{
double rand = _random.NextDouble();
double value = _min + (rand * _range);
return (T)Convert.ChangeType(value, ElementType);
}
}

class Program
{
static void Main(string[] args)
{
RangedRandom<int> random = new RangedRandom<int>(10, 50);

int count = 20;

while (count-- > 0)
{
Console.WriteLine(random.Next());
}
}
}


Note the RangedRandom class imposes the restriction that the type must implement IConvertible, so System.Convert will work.

Darwen.

toraj58
January 25th, 2009, 12:06 PM
where T : struct is good constraint for this case.

darwen
January 25th, 2009, 03:57 PM
where T : struct is good constraint for this case


Actually, no it's not because this will compile ok with a struct constraint, but will throw a compile error with a IConvertible constraint.


struct MyStruct
{
int a;
double b;
}

MyStruct min = new MyStruct();
MyStruct max = new MyStruct();

RangedRandom<MyStruct> rr = new RangedRandom<MyStruct>(min, max);


So an IConvertible constraint is better.

Darwen.

THY02K
January 25th, 2009, 07:06 PM
This is exactly what I was looking for, many Thanks Darwen!

darwen
January 25th, 2009, 07:30 PM
Your welcome.

Remember the IConvertible constraint trick : I tend to find myself doing a lot of conversions between standard types (i.e. int, double etc) in my generic classes, and I find this is a good way of adding some type safety so that errors are picked up at compile time and not runtime.

Darwen.