471,330 Members | 1,752 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,330 software developers and data experts.

Generics Questions

Udi
Hi All,
Two questions regarding Generics:

1. I'd like to constrain my Type parameter to be one of a preefined
group of types. For example:

class Field<Twhere T: Byte, Int, String, Array<byte{}

- Meaning T can by either Byte, Int String or Array<byte>.

Is there a way to force a type to this constraint?

2. I have a buffer that represents one of the above types.
I'd like to add a method to get the value from the buffer.
I was hoping to do something like this:

public T GetFieldValue(byte [] buffer)
{
switch(fieldType)
{
case byte:
{
return buffer[offset]; //Error can't cast
byte to T
}
case int:
{
return (T)BitConverter.ToInt32(buffer, offset); //
Error can't cast int to T
}
:
:
}
}
The problem is that the compiler can't cast from my type to T.
Any ideas on how to solve this?
(I would like to prevent the caller to GetFieldValue() from using
another switch/case statement on result type.)

Thanks!
Udi.


Jul 27 '08 #1
10 1264
No; use overloads instead - i.e. have a method pair for each of the 4
types.

Marc
Jul 27 '08 #2
For info, one other approach is to pass in (or register centrally) an
interface-implementation per type - i.e. you might have an;

interface IByteConverter<T{
T ReadFromBuffer(byte[] buffer, int offset);
int WriteToBuffer(T value, byte[] buffer. int offset);
}

You then might have 4 concrete implementations of this, each doing
their own thing. You can either pass the implementation into the
method as a parameter, or you could register them against a generic
cache class:

static ByteConverter<T{
public T Default {get;set;}
}

and have a bit of code assign:

ByteConverter<int= new Int32ByteConverter();
ByteConverter<string= new StringByteConverter();

I use a similar approach in my "protobuf-net" implementation:
http://code.google.com/p/protobuf-ne...et/Serializers

(look at ISerializer and SerializerCache, etc; the rest are
differerent implementations)

Marc
Jul 27 '08 #3
ByteConverter<int= new Int32ByteConverter();
ByteConverter<string= new StringByteConverter();
(add a .Default in there - I missed it out...)
Jul 27 '08 #4
and should have been:

static ByteConverter<T{
public IByteConverter<TDefault {get;set;}
}

i.e. for any T you can try to get the converter via
ByteConverter<T>.Default; if it is null you can't hadle the type, so
throw an exception.
Jul 27 '08 #5
Udi
On Jul 27, 4:17*pm, Marc Gravell <marc.grav...@gmail.comwrote:
and should have been:

static ByteConverter<T{
* public IByteConverter<TDefault {get;set;}

}

i.e. for any T you can try to get the converter via
ByteConverter<T>.Default; if it is null you can't hadle the type, so
throw an exception.
Thanks for the help!
Indeed I was thinking about using an interface.
In your example however, don't I end up with the same problem inside
ReadFromBuffer()?
I won't be able to cast back to my there as well will I?
What am I missing?

Jul 27 '08 #6
In your example however, don't I end up with the same problem inside
ReadFromBuffer()?
I won't be able to cast back to my there as well will I?
What am I missing?
Each implementation is specific to the type it is designed for, so
there /is/ no cast, or if there is it is a well-defined one; for
example:

public class SingleByteConverter : IByteConverter<float{
public float ReadFromBuffer(byte[] buffer, int offset) {
return BitConverter.ToSingle(buffer, offset);
}
public int WriteToBuffer(float value, byte[] buffer, int offset) {
byte[] tmp = BitConverter.GetBytes(value);
buffer[offset++] = tmp[0];
buffer[offset++] = tmp[1];
buffer[offset++] = tmp[2];
buffer[offset] = tmp[3];
return 4; // how many bytes we wrote
}
}

So there might be 4 different classes, each just implementing
IByteConverter< something (for a different something).
Note that it is possible for a single class to support multiple
primates using explicit interface implementation; that is what the
various Foo_Bar files are (in the pervious link).

Of course, if you simply want to provide a binary serialization for
your classes, you could consider protobuf-net ;-p

Marc
Jul 27 '08 #7
Aside from all the good suggestions the others have already given you
(and you are probably better off using them in this specific case),
here's some info which might be useful in general.

On Jul 27, 4:53*pm, Udi <UdiBenSen...@gmail.comwrote:
1. I'd like to constrain my Type parameter to be one of a preefined
group of types. For example:

* * class Field<Twhere T: Byte, Int, String, Array<byte{}

* * - Meaning T can by either Byte, Int String or Array<byte>.

* * Is there a way to force a type to this constraint?
No.
2. I have a buffer that represents one of the above types.
* * I'd like to add a method to get the value from the buffer.
* * I was hoping to do something like this:

* *public T GetFieldValue(byte [] buffer)
* *{
* * * switch(fieldType)
* * * {
* * * * * case byte:
* * * * * {
* * * * * * * * return buffer[offset]; * * * * *//Error can't cast
byte to T
* * * * * }
* * * * * case int:
* * * * * {
* * * * * * * * *return (T)BitConverter.ToInt32(buffer,offset); * //
Error can't cast int to T
* * * * * }
* * * * * :
* * * * * :
* * *}
* }

* *The problem is that the compiler can't cast from my type to T.
* *Any ideas on how to solve this?
Yes. First of all, you can't use switch the way you used it, but you
can use if and typeof:

if (typeof(T) == typeof(byte)) { ... }
else if (typeof(T) == typeof(int)) { ... }

What's even more interesting is that, in my experience, the JIT
compiler will actually figure out that the check is always true (or
always false) for a particular T, and will optimize away all checks,
leaving only the proper branch for the type - meaning that there's no
performance penalty.

Now the second thing, the fact that you can't cast a specific type to
T (or the other way around). This is because T may be a class, and
cast operator in C# does not allow cross-casting from a class to
another class, only between interfaces - for classes, there must be a
known inheritance relationship between them. The only way to work
around this that I know of is to first cast to Object, i.e.:

return (T)(object)byte;

Unfortunately, this is not optimized away, so you get an extra type
check for reference types if you do that, and boxing/unboxing on top
of that check for value types - and that is quite expensive.
Jul 28 '08 #8
Udi
On Jul 28, 10:45*am, Pavel Minaev <int...@gmail.comwrote:
Aside from all the good suggestions the others have already given you
(and you are probably better off using them in this specific case),
here's some info which might be useful in general.

On Jul 27, 4:53*pm,Udi<UdiBenSen...@gmail.comwrote:
1. I'd like to constrain my Type parameter to be one of a preefined
group of types. For example:
* * class Field<Twhere T: Byte, Int, String, Array<byte{}
* * - Meaning T can by either Byte, Int String or Array<byte>.
* * Is there a way to force a type to this constraint?

No.


2. I have a buffer that represents one of the above types.
* * I'd like to add a method to get the value from the buffer.
* * I was hoping to do something like this:
* *public T GetFieldValue(byte [] buffer)
* *{
* * * switch(fieldType)
* * * {
* * * * * case byte:
* * * * * {
* * * * * * * * return buffer[offset]; * * * * *//Error can't cast
byte to T
* * * * * }
* * * * * case int:
* * * * * {
* * * * * * * * *return (T)BitConverter.ToInt32(buffer, offset); * //
Error can't cast int to T
* * * * * }
* * * * * :
* * * * * :
* * *}
* }
* *The problem is that the compiler can't cast from my type to T.
* *Any ideas on how to solve this?

Yes. First of all, you can't use switch the way you used it, but you
can use if and typeof:

if (typeof(T) == typeof(byte)) { ... }
else if (typeof(T) == typeof(int)) { ... }

What's even more interesting is that, in my experience, the JIT
compiler will actually figure out that the check is always true (or
always false) for a particular T, and will optimize away all checks,
leaving only the proper branch for the type - meaning that there's no
performance penalty.

Now the second thing, the fact that you can't cast a specific type to
T (or the other way around). This is because T may be a class, and
cast operator in C# does not allow cross-casting from a class to
another class, only between interfaces - for classes, there must be a
known inheritance relationship between them. The only way to work
around this that I know of is to first cast to Object, i.e.:

* return (T)(object)byte;

Unfortunately, this is not optimized away, so you get an extra type
check for reference types if you do that, and boxing/unboxing on top
of that check for value types - and that is quite expensive.- Hide quotedtext -

- Show quoted text -
Thanks for the info!
Jul 29 '08 #9
Marc Gravell wrote:
For info, one other approach is to pass in (or register centrally) an
interface-implementation per type - i.e. you might have an;

interface IByteConverter<T{
T ReadFromBuffer(byte[] buffer, int offset);
int WriteToBuffer(T value, byte[] buffer. int offset);
}

You then might have 4 concrete implementations of this, each doing
their own thing. You can either pass the implementation into the
method as a parameter, or you could register them against a generic
cache class:

static ByteConverter<T{
public T Default {get;set;}
}

and have a bit of code assign:

ByteConverter<int= new Int32ByteConverter();
ByteConverter<string= new StringByteConverter();
This is really good if you want to leave it open for extension by the user.

If you don't care, then... nevermind, you can't inherit a public class from
an internal abstract class due to restrictions in .NET.
>
I use a similar approach in my "protobuf-net" implementation:
http://code.google.com/p/protobuf-ne...et/Serializers

(look at ISerializer and SerializerCache, etc; the rest are
differerent implementations)

Marc

Jul 29 '08 #10
If you don't care, then... nevermind, you can't inherit a public class from
an internal abstract class due to restrictions in .NET.
Even just for internal use it can be handy; it means you don't have to
keep writing switches to choose between implementations; you just use
the registered Something<T>.Handler etc...

Marc
Jul 29 '08 #11

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

23 posts views Thread by Luc Vaillant | last post: by
9 posts views Thread by sloan | last post: by
18 posts views Thread by riftimes | last post: by
3 posts views Thread by LongBow | last post: by
10 posts views Thread by Frank Rizzo | last post: by
13 posts views Thread by rkausch | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.