By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,492 Members | 1,199 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,492 IT Pros & Developers. It's quick & easy.

explicit cast between generic types

P: n/a
Jon
Hi,

When I try to compile the following generic class, the compiler gives
me many errors "Cannot conver type '...' to '...'" on the lines
indicated. Besides, the C# compiler gives me errors even if I don't
declare and instantiate C_Filter_MA<Ti,Tsin my program.
Ti and Ts should be one of {Byte, UInt16, UInt32, UInt64, SByte,
Int16, Int32, Int64, double}.

Any clue on how to be able to compile this class?
Thank you very much.

// ================================================== ============
public class C_Filter_MA<Ti,Ts>
{
// .................................................. ..........
protected Queue<Ti Ti_queue; // Queue (FIFO) that stores the
items.
protected Ts Ts_sum; // Sum of the values stored in the
queue.
...
// .................................................. ..........
...
// .................................................. ..........
public void Clear()
{
...
Ts_sum =(Ts)0; // <-- Compile error.
...
} // Clear
// .................................................. ..........
public Ti InOutData(Ti Ti_in)
{
...
Ts_sum -=(Ts)Ti_queue.Dequeue(); // <-- Compile error.
...
Ts_sum +=(Ts)Ti_in; // <-- Compile error.
...
} // InOutData
// .................................................. ..........
} // C_Filter_MA
// ================================================== ============

Dec 10 '07 #1
Share this Question
Share on Google+
6 Replies


P: n/a
Jon,

Why do you have two types to begin with? How is it that the sum of
types Ti equals a ^NEW^ type Ts? Why wouldn't you just need one type, Ti?

As for the Clear method, you can fix this by using default:

public void Clear()
{
// This should probably be Ti, the same could be applied.
Ts_sum = default(Ti);
} // Clear

If Ti is a blittable type, then an instance of that type will be created
with the data set to 0 for all bits in the type. In the case of int,
double, etc, etc, that means values of 0.

Changing to Ti will fix the Dequeue issue as well.

As for adding, you aren't going to be able to do much with that, since
the constraint system doesn't tell the compiler anything about operations on
a type. Because of this, you will need another class that handles this.
First, you have to define an interface like this:

interface ISimpleMath<T>
{
T Add(T value1, T value2);
T Subtract(T value1, T value2);
}

Then, you implement it for each of the types you want to use, like so:

class IntSimpleMath: ISimpleMath<int>
{
public int Add(int value1, int value2)
{
// Return the sum.
return value1 + value2;
}

public int Subtract(int value1, int value2)
{
// Return the difference.
return value1 - value2;
}
}

Finally, you would add a second type to your generic type which would
indicate the type used to perform the adding:

public class C_Filter_MA<Ti, TSimpleMathwhere TSimpleMath:
ISimpleMath<Ti>, new()
{
// Assuming that the operations on the implementation of ISimpleMath are
thread-safe (and
// they should be, since you are passing all operands into the method
and not storing
// shared state), you can store one instance and use that across all
instances of the type.
private static readonly SimpleMathImplementation = new TSimpleMath();

// .................................................. ..........
protected Queue<Ti Ti_queue; // Queue (FIFO) that stores the items.

// Changed to be of type Ti.
protected Ti Ts_sum; // Sum of the values stored in the queue.

public void Clear()
{
Ts_sum = default(Ti)
} // Clear

public Ti InOutData(Ti Ti_in)
{
// Get the item.
Ti item = Ti_queue.Dequeue();

// Subtract from the sum.
Ts_sum = SimpleMathImplementation.Subtract(Ts_sum, item);

// Add the item passed in.
Ts_sum = SimpleMathImplementation.Add(Ts_sum, Ti_in);
} // InOutData
} // C_Filter_MA
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Jon" <jm*@hotmail.comwrote in message
news:mp********************************@4ax.com...
Hi,

When I try to compile the following generic class, the compiler gives
me many errors "Cannot conver type '...' to '...'" on the lines
indicated. Besides, the C# compiler gives me errors even if I don't
declare and instantiate C_Filter_MA<Ti,Tsin my program.
Ti and Ts should be one of {Byte, UInt16, UInt32, UInt64, SByte,
Int16, Int32, Int64, double}.

Any clue on how to be able to compile this class?
Thank you very much.

// ================================================== ============
public class C_Filter_MA<Ti,Ts>
{
// .................................................. ..........
protected Queue<Ti Ti_queue; // Queue (FIFO) that stores the
items.
protected Ts Ts_sum; // Sum of the values stored in the
queue.
...
// .................................................. ..........
...
// .................................................. ..........
public void Clear()
{
...
Ts_sum =(Ts)0; // <-- Compile error.
...
} // Clear
// .................................................. ..........
public Ti InOutData(Ti Ti_in)
{
...
Ts_sum -=(Ts)Ti_queue.Dequeue(); // <-- Compile error.
...
Ts_sum +=(Ts)Ti_in; // <-- Compile error.
...
} // InOutData
// .................................................. ..........
} // C_Filter_MA
// ================================================== ============

Dec 10 '07 #2

P: n/a
Ts_sum -=(Ts)Ti_queue.Dequeue(); // <-- Compile error.
Ts_sum +=(Ts)Ti_in; // <-- Compile error.

For info, I have a working generic math implementation as an in-
progress side project. It includes standard operators and conversion;
it runtime (not compile-time) validated but is very fast.

I posted some of it on this forum previously, but let me know if this
is of interest.

Marc
Dec 10 '07 #3

P: n/a
Jon
Hi Nicholas,

I tried your custom interface solution. I end up with only 4 compile
erros, in two lines. Search for token "errors" in the source code
shown below. In line

private static readonly Ts_SimpleMathImplementation= new
Ts_SimpleMath();

it is like it doesn't know how to create a new instance of
Ts_SimpleMath. The "new ()" in line

where Ti_SimpleMath : I_SimpleMath<Ti>, new()

presumably means that Ti_SimpleMath must have a public parameterless
constructor. How can I specify the constructor of Ti_SimpleMath ? In
I_SimpleMath<T>? How?

I know that I ended up not using "Ti_SimpleMathImplementation", but I
would keep it just in case. I do use "Ts_SimpleMathImplementation".

Sorry about the long post.

If you know why I'm getting those errors, please let me know.
Thank you.

PS: I'm starting to think about not using generics for this purpose,
and instead define two or three classes like "C_Filter_MA_u08_u32",
"C_Filter_MA_u16_u32" and "C_Filter_MA_double_double", for instance,
because I'll probably end up with fewer lines of code. All this has
really surprised me.
---------------------------------------
using System;
using System.Collections.Generic;

// These "using" are the C# equivalent ones to "typedef" in C++.
using u08 =System.Byte;
using u16 =System.UInt16;
using u32 =System.UInt32;
using u64 =System.UInt64;

using i08 =System.SByte;
using i16 =System.Int16;
using i32 =System.Int32;
using i64 =System.Int64;

namespace N_Filters
{
#region Interfaces and their implementations.
// ================================================== =============
// Interfaces cannot contain operators.
public interface I_SimpleMath<T>
{
T Add(T val1, T val2);
T Subtract(T val1, T val2);
T Multiply(T val1, T val2);
T Divide(T val1, T val2);
T ShiftLeft(T val1,u08 shift_amount);
T ShiftRight(T val1,u08 shift_amount);
} // I_SimpleMath
// ================================================== =============
public class C_SimpleMath_u08 : I_SimpleMath<u08>
{
public u08 Add(u08 val1, u08 val2)
{
return((u08)(val1+val2));
}
public u08 Subtract(u08 val1, u08 val2)
{
return((u08)(val1-val2));
}
public u08 Multiply(u08 val1, u08 val2)
{
return((u08)(val1*val2));
}
public u08 Divide(u08 val1, u08 val2)
{
return((u08)(val1/val2));
}
public u08 ShiftLeft(u08 val1,u08 shift_amount)
{
return((u08)(val1<<shift_amount));
}
public u08 ShiftRight(u08 val1,u08 shift_amount)
{
return((u08)(val1>>shift_amount));
}
} // C_SimpleMath_u08
// ================================================== =============
public class C_SimpleMath_u16 : I_SimpleMath<u16>
{
public u16 Add(u16 val1, u16 val2)
{
return((u16)(val1+val2));
}
public u16 Subtract(u16 val1, u16 val2)
{
return((u16)(val1-val2));
}
public u16 Multiply(u16 val1, u16 val2)
{
return((u16)(val1*val2));
}
public u16 Divide(u16 val1, u16 val2)
{
return((u16)(val1/val2));
}
public u16 ShiftLeft(u16 val1,u08 shift_amount)
{
return((u16)(val1<<shift_amount));
}
public u16 ShiftRight(u16 val1,u08 shift_amount)
{
return((u16)(val1>>shift_amount));
}
} // C_SimpleMath_u16
// ================================================== =============
public class C_SimpleMath_u32 : I_SimpleMath<u32>
{
public u32 Add(u32 val1, u32 val2)
{
return((u32)(val1+val2));
}
public u32 Subtract(u32 val1, u32 val2)
{
return((u32)(val1-val2));
}
public u32 Multiply(u32 val1, u32 val2)
{
return((u32)(val1*val2));
}
public u32 Divide(u32 val1, u32 val2)
{
return((u32)(val1/val2));
}
public u32 ShiftLeft(u32 val1,u08 shift_amount)
{
return((u32)(val1<<shift_amount));
}
public u32 ShiftRight(u32 val1,u08 shift_amount)
{
return((u32)(val1>>shift_amount));
}
} // C_SimpleMath_u32
// ================================================== =============
public class C_SimpleMath_u64 : I_SimpleMath<u64>
{
public u64 Add(u64 val1, u64 val2)
{
return((u64)(val1+val2));
}
public u64 Subtract(u64 val1, u64 val2)
{
return((u64)(val1-val2));
}
public u64 Multiply(u64 val1, u64 val2)
{
return((u64)(val1*val2));
}
public u64 Divide(u64 val1, u64 val2)
{
return((u64)(val1/val2));
}
public u64 ShiftLeft(u64 val1,u08 shift_amount)
{
return((u64)(val1<<shift_amount));
}
public u64 ShiftRight(u64 val1,u08 shift_amount)
{
return((u64)(val1>>shift_amount));
}
} // C_SimpleMath_u64
// ================================================== =============
public class C_SimpleMath_i08 : I_SimpleMath<i08>
{
public i08 Add(i08 val1, i08 val2)
{
return((i08)(val1+val2));
}
public i08 Subtract(i08 val1, i08 val2)
{
return((i08)(val1-val2));
}
public i08 Multiply(i08 val1, i08 val2)
{
return((i08)(val1*val2));
}
public i08 Divide(i08 val1, i08 val2)
{
return((i08)(val1/val2));
}
public i08 ShiftLeft(i08 val1,u08 shift_amount)
{
return((i08)(val1<<shift_amount));
}
public i08 ShiftRight(i08 val1,u08 shift_amount)
{
return((i08)(val1>>shift_amount));
}
} // C_SimpleMath_i08
// ================================================== =============
public class C_SimpleMath_i16 : I_SimpleMath<i16>
{
public i16 Add(i16 val1, i16 val2)
{
return((i16)(val1+val2));
}
public i16 Subtract(i16 val1, i16 val2)
{
return((i16)(val1-val2));
}
public i16 Multiply(i16 val1, i16 val2)
{
return((i16)(val1*val2));
}
public i16 Divide(i16 val1, i16 val2)
{
return((i16)(val1/val2));
}
public i16 ShiftLeft(i16 val1,u08 shift_amount)
{
return((i16)(val1<<shift_amount));
}
public i16 ShiftRight(i16 val1,u08 shift_amount)
{
return((i16)(val1>>shift_amount));
}
} // C_SimpleMath_i16
// ================================================== =============
public class C_SimpleMath_i32 : I_SimpleMath<i32>
{
public i32 Add(i32 val1, i32 val2)
{
return((i32)(val1+val2));
}
public i32 Subtract(i32 val1, i32 val2)
{
return((i32)(val1-val2));
}
public i32 Multiply(i32 val1, i32 val2)
{
return((i32)(val1*val2));
}
public i32 Divide(i32 val1, i32 val2)
{
return((i32)(val1/val2));
}
public i32 ShiftLeft(i32 val1,u08 shift_amount)
{
return((i32)(val1<<shift_amount));
}
public i32 ShiftRight(i32 val1,u08 shift_amount)
{
return((i32)(val1>>shift_amount));
}
} // C_SimpleMath_i32
// ================================================== =============
public class C_SimpleMath_i64 : I_SimpleMath<i64>
{
public i64 Add(i64 val1, i64 val2)
{
return((i64)(val1+val2));
}
public i64 Subtract(i64 val1, i64 val2)
{
return((i64)(val1-val2));
}
public i64 Multiply(i64 val1, i64 val2)
{
return((i64)(val1*val2));
}
public i64 Divide(i64 val1, i64 val2)
{
return((i64)(val1/val2));
}
public i64 ShiftLeft(i64 val1,u08 shift_amount)
{
return((i64)(val1<<shift_amount));
}
public i64 ShiftRight(i64 val1,u08 shift_amount)
{
return((i64)(val1>>shift_amount));
}
} // C_SimpleMath_i64
// ================================================== =============
public class C_SimpleMath_double : I_SimpleMath<double>
{
public double Add(double val1, double val2)
{
return((double)(val1+val2));
}
public double Subtract(double val1, double val2)
{
return((double)(val1-val2));
}
public double Multiply(double val1, double val2)
{
return((double)(val1*val2));
}
public double Divide(double val1, double val2)
{
return((double)(val1/val2));
}
public double ShiftLeft(double val1,u08 shift_amount)
{
return(val1*Math.Pow(2.0,(double)shift_amount));
}
public double ShiftRight(double val1,u08 shift_amount)
{
return(val1*Math.Pow(2.0,(double)shift_amount*-1.0));
}
} // C_SimpleMath_double
#endregion
// ================================================== =============
// Moving average filter.
// Ti = T_item {u08,u16,u32,u64,i08,i16,i32,i64,double}.
// Ts = T_sum {u08,u16,u32,u64,i08,i16,i32,i64,double}.

public class C_Filter_MA<Ti,Ti_SimpleMath,Ts,Ts_SimpleMath>
where Ti : IComparable, IFormattable, IConvertible,
IComparable<Ti>, IEquatable<Ti>
where Ti_SimpleMath : I_SimpleMath<Ti>, new()
where Ts : IComparable, IFormattable, IConvertible,
IComparable<Ts>, IEquatable<Ts>
where Ts_SimpleMath : I_SimpleMath<Ts>, new()
{
// .................................................. ...........
private static readonly Ti_SimpleMathImplementation= new
Ti_SimpleMath(); // <-- Compile errors "Invalid token '=' in class,
struct, or interface member declaration" and "Class, struct, or
interface method must have a return type".
private static readonly Ts_SimpleMathImplementation= new
Ts_SimpleMath(); // <-- Compile errors "Invalid token '=' in class,
struct, or interface member declaration" and "Class, struct, or
interface method must have a return type".
// .................................................. ...........
protected Queue<Ti Ti_queue; // Queue (FIFO) that
stores the items.
public int Ti_queue_capacity; // Queue does not
have any member field called Capacity.
protected Ts Ts_sum; // Sum of the values
stored in the queue.
protected u08 u08_log2ofsize; // Log2(<size of
fifo>). So, size of fifo will always be a power of 2.
// .................................................. ...........
public C_Filter_MA(u08 u08_log2ofsize)
{
this.u08_log2ofsize=u08_log2ofsize;
Ti_queue_capacity=1<<u08_log2ofsize;
Ti_queue=new Queue<Ti>(Ti_queue_capacity);
Clear();
} // C_Filter_MA
// .................................................. ...........
public void Clear()
{
Ti_queue.Clear();
Ts_sum=default(Ts);
} // Clear
// .................................................. ...........
public void Init(Ti Ti_initial)
{
Ti_queue.Clear();

Ts_sum=(Ts)Convert.ChangeType(Ti_initial.ToInt32() *Ti_queue_capacity,typeof(Ts));
if (Ti_initial.Equals(default(Ti))) return;
for (int i=0;i<Ti_queue_capacity;i++)
{
Ti_queue.Enqueue(Ti_initial);
} // for
} // Init
// .................................................. ...........
public Ti InOutData(Ti Ti_in)
{
if (Ti_queue.Count>=Ti_queue_capacity)
{

Ts_sum=Ts_SimpleMathImplementation.Subtract(Ts_sum ,(Ts)Convert.ChangeType(Ti_queue.Dequeue(),typeof( Ts)));
} // if
Ti_queue.Enqueue(Ti_in);

Ts_sum=Ts_SimpleMathImplementation.Add(Ts_sum,(Ts) Convert.ChangeType(Ti_in,typeof(Ts)));
return(
(Ti)Convert.ChangeType(Ts_SimpleMathImplementation .ShiftRight(Ts_sum,u08_log2ofsize),typeof(Ti))
);
} // InOutData
// .................................................. ...........
} // C_Filter_MA
// ================================================== =============
} // N_Filters

Dec 11 '07 #4

P: n/a
Jon
On Mon, 10 Dec 2007 14:27:33 -0800 (PST), Marc Gravell
<ma**********@gmail.comwrote:
Ts_sum -=(Ts)Ti_queue.Dequeue(); // <-- Compile error.
Ts_sum +=(Ts)Ti_in; // <-- Compile error.

For info, I have a working generic math implementation as an in-
progress side project. It includes standard operators and conversion;
it runtime (not compile-time) validated but is very fast.

I posted some of it on this forum previously, but let me know if this
is of interest.

Marc
Even though I prefer compile-time validation, I would be glad to take
a look at your implementation. If you have a link, please let me know.
Otherwise, please write me at "cucafera (at) telefonica (dot) com"

Thank you.

Dec 11 '07 #5

P: n/a
I have e-mailed you a sample, but I've also just noticed that you
mention CF. Unfortunately, the code doesn't compile in CF 3.5, as it
uses some framework classes that aren't supported on that platform. It
may be possible to re-work the concept using Delegate.CreateDelegate
and the various operators, but there are a lot of special cases where
the operator is supplied by the compiler (not the Type) which would
need surrogate methods (which is partly what I was hoping to avoid).

Marc
Dec 11 '07 #6

P: n/a
but that didn't work either. It still doesn't know how to add or
subtract. My quesion is: Isn't there any existing interface, which
would be common to the integral and floating point types, which
exposes methods so common as adding, subtracting, multiplying, etc?
You've just nailed the biggest complaint about generics.
Dec 31 '07 #7

This discussion thread is closed

Replies have been disabled for this discussion.