wrap overloading function with generics - c#

I want to wrap BitConverter with some extra functionalities. But I don't have to write out all the overloading functions like
BitConverter.GetBytes(int);
BitConverter.GetBytes(double);
...
Is there a way to write a single template function that wraps all the overloading functions? like
void GetBytes <T> (List<byte> byteList, T value)
{
....
byte[] result = BitConverter.GetBytes(value);
byteList.AddRange(result);
return;
}

You could write an extension method for IEnumerable<byte> I suppose:
class Program
{
static void Main(string[] args)
{
var target = new List<byte>();
BitConverter.GetBytes(10).AddBytesToTarget(target);
BitConverter.GetBytes(100d).AddBytesToTarget(target);
}
}
static public class Extensions
{
public static void AddBytesToTarget(this IEnumerable<byte> bytes, List<byte> target)
{
target.AddRange(bytes);
}
}

You cannot do it with generics since the overload resolution BitConverter.GetBytes will fail since T can be any type.
You could do it with dynamic:
void GetBytes(List<byte> byteList, dynamic value) {
....
byte[] result = BitConverter.GetBytes(value);
byteList.AddRange(result);
}
This will defer the overload resolution until runtime. Of course this also pushes type checking so if an invalid type was used for value you would get a runtime exception instead of a compiler error.

You can use dynamic type
Read this link of MSDN

Related

How to use generics to pass argument to a non-generic method?

Why does the following code not compile?
How can I create a generic method which calls the appropriate "BitConverter.GetBytes" overload based on if the generic type is an "int", "bool", "char", etc.?
More generally, how can I create a generic method which calls a non-generic method based on the generic parameter's type?
using System;
public class Test
{
public static void Main()
{
var f = new Foo();
f.GetBytes(10); // should call BitConverter.GetBytes(int);
f.GetBytes(true); // should call BitConverter.GetBytes(bool);
f.GetBytes('A'); // should call BitConverter.GetBytes(char);
}
}
public class Foo
{
public byte[] GetBytes <TSource> (TSource input)
{
BitConverter.GetBytes(input);
}
}
More generally, how can I create a generic method which calls a non-generic method based on the generic parameter's type?
In general, you can't, unless the method in question takes System.Object as a parameter. The problem is that the generic isn't constrained to just types that would be allowed by the method call arguments.
The closest you can do is to use runtime binding:
public byte[] GetBytes <TSource> (TSource input)
{
dynamic obj = input;
BitConverter.GetBytes(obj);
}
This pushes the method binding logic to runtime, and will throw if there isn't an appropriate method to call.
The reason this doesn't work is that generic methods still resolve calls to methods made within them statically. Since TSource could be any type at all, it can only call a method on BitConverter which takes an object argument. Since none exists, the compilation fails.
The only way to get the behaviour you want to is to use dynamic:
public byte[] GetBytes <TSource> (TSource input)
{
BitConverter.GetBytes((dynamic)input);
}
although the generic parameter is now redundant and you have no type safety.
In this situation you can either create a number of matching overloads e.g.
public byte[] GetBytes(bool b) { ... }
public byte[] GetBytes(int i) { ... }
or take a Func<T, byte[]> argument and wrap each BitConverter method you need e.g.
public void DoSomething<T>(T input, Func<T, byte[]> f)
{
byte[] bytes = f(input);
//handle bytes
}
DoSomething(true, BitConverter.GetBytes);
which may give you more flexibility.
Where the code is calling BitConverter.GetBytes, the type is TSource, so the call can't be statically bound by the compiler. You can work around this using dynamic invocation, meaning it'll compile fine and then get resolved at runtime:
…
public byte[] GetBytes(dynamic input)
{
return BitConverter.GetBytes(input);
}
You will pay a performance penalty for using dynamic invocation and if no suitable method to call is available you will get a runtime exception.
Given that there are "only" 10 overloads of BitConverter.GetBytes, it's not impossible to reflect them all explicitly like this:
public class Foo
{
public byte[] GetBytes(bool input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(char input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(double input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(float input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(int input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(short input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(long input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(uint input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(ulong input) { return BitConverter.GetBytes(input); }
public byte[] GetBytes(ushort input) { return BitConverter.GetBytes(input); }
}
It's not generic (which you had asked for), and isn't scalable to more complex examples, but if the numbers are small then it's an approach to consider.
If you are willing to take a performance hit, you can use reflection and an extension to object called GetBytes. example....
public static class Extensions
{
#region Fields
public static Type bcType;
#endregion
#region Constructor
static Extensions()
{
bcType = typeof(BitConverter);
}
#endregion
public static byte[] GetBytes(this object value)
{
Type typeObj = value.GetType();
MethodInfo miGetBytes = bcType.GetMethod("GetBytes", new Type[] { typeObj });
if (miGetBytes == null)
throw new InvalidOperationException("Method: GetBytes on BitConverter does not have an overload accepting one paramter of type: " + typeObj.FullName);
byte[] bytesRet = (byte[])miGetBytes.Invoke(null, new object[] { obj });
return bytesRet;
}
}
So GetBytes accepts an object. Then it get's it's type and tries to get the MethodInfo from BitConverter based on the type of object passed in. If it can't find an overload that accepts that type as a parameter it throws an InvalidOperation Exception. If it does, it calls it passing in the instance of obj as the value and returns the byte array.
E.g. Usage code,
//make sure the extensions namespace is defined where this code is run.
Console.WriteLine(((ushort)255).GetBytes().ToBase64());
Console.WriteLine(10.0.GetBytes().ToBase64());
Console.WriteLine(((int)2000000000).GetBytes().ToBase64());
Console.WriteLine(((short)128).GetBytes().ToBase64());
//Below causes an error
Console.WriteLine("cool".GetBytes().ToBase64()); //because BitConvert.GetBytes has no overload accepting an argument of type string.
You'll need to use reflection to do that.
Get the GetBytes method group from the BitConverter static type.
Pull out the overload for which the first parameter has type TSource.
Call that specific method via the Invoke method.
If you aren't familiar with some of this, I can expand the answer with code for those steps.
Edit: Or just use dynamic like others are suggesting and save yourself some work.
Your code doesn't compile because the compiler can't verify that any type for TSource will be accepted by BitConverter.GetBytes(). You can check for each type individually and cast:
public byte[] GetBytes <TSource> (TSource input)
{
var t = typeof(TSource);
return (t == typeof(int)) ? BitConverter.GetBytes((int) (object) input)
: (t == typeof(bool)) ? BitConverter.GetBytes((bool)(object) input)
: (t == typeof(char)) ? BitConverter.GetBytes((char)(object) input)
: null;
}

calling an overloaded method in generic method

class Test
{
public BinaryWriter Content { get; private set; }
public Test Write<T> (T data)
{
Content.Write(data);
return this;
}
}
it won't compile.
1. The best overloaded method match for 'System.IO.BinaryWriter.Write(bool)' has some invalid arguments
2. Argument 1: cannot convert from 'T' to 'bool'
it seems like Test.Write is always trying to call BinaryWriter.Write(bool). any suggestions?
Overload resolution happens at compile-time, and in this case nothing is known about T, so no overload is applicable.
class Test
{
public BinaryWriter Content { get; private set; }
public Test Write<T>(T data)
{
Content.Write((dynamic)data);
return this;
}
}
But of course it could make some problems. For example, appliction will compile fine, if you will send DateTime to the method. But, it will throw exception.
This is possible but not with generic constraints . You can try to use Reflection and get the appropriate overloaded version of Write method according to type of T.
Initialize your BinaryWriter with a Stream in your constructor then use Reflection like below:
class Test
{
public BinaryWriter Content { get; private set; }
public Test(Stream stream)
{
Content = new BinaryWriter(stream);
}
public Test Write<T>(T data)
{
var method = typeof (BinaryWriter).GetMethod("Write", new[] {data.GetType()});
if (method != null)
{
method.Invoke(Content, new object[] { data });
}
// here you might want to throw an exception if method is not found
return this;
}
}
Here is a test program:
Test writer;
using (var fs = new FileStream("sample.txt", FileMode.Open))
{
writer = new Test(fs);
writer = writer.Write(232323);
writer = writer.Write(true);
writer = writer.Write(12);
}
using (var fs = File.Open("sample.txt", FileMode.Open))
{
var reader = new BinaryReader(fs);
Console.WriteLine(reader.ReadInt32()); // 232323
Console.WriteLine(reader.ReadBoolean()); // true
Console.WriteLine(reader.ReadByte()); // 12
}
In your write method T is generic, which means that T can be anything, but BinaryWriter.Write doesn't takes a generic overload. So you can't do that.
You can't do that.
Since real type of T is unknown at compile-time, compiler can't find appropriate Write overload, and tries to call the first found one. There is no overload, which could be called with any type of T (e.g., Write(object)).
Using Reflection considerably slows down method calls. It also moves argument type check from compile time to runtime, which is undesirable in most cases.
Using dynamic calls in this case is just a fancy and slightly optimized version of the previous method which has the same drawbacks.
The correct way is to copy all overloads:
public Test Write (bool data)
{
Content.Write(data);
return this;
}
public Test Write (byte data)
{
Content.Write(data);
return this;
}
public Test Write (byte[] data)
{
Content.Write(data);
return this;
}
public Test Write (char data)
{
Content.Write(data);
return this;
}
public Test Write (char[] data)
{
Content.Write(data);
return this;
}
// ...
This method is very verbose, but it is the only that provides compile-time checks of arument types and is the most performant as it chooses overloads and compile-time. Furthermore, these methods are likely to be inlined.
In cases like this, I usually use a T4 script which generates code like above based on Reflection. Create a TT file, enumerate Write overloads of BinaryWriter, generate code.

C# Method overloading using dynamic params

I'm trying to write a tool for serialization of values. And I was hoping to get some nice syntax working.....
float f = 9999.0f;
ByteSerializer s = new ByteSerializer ();
s.Write(f);
Where the params of Write() could be anything and any number:
public void Write (params dynamic[] objects)
{
for (int i =0;i<objects.Length;i++) {
byteList.AddRange (GetBytes (objects[i]));
}
}
GetBytes() should now be called according to the type of the object that was passed:
public byte[] GetBytes ( object v)
{
//Shouldn't actually do anything since it's a dummy
return new byte[0];
}
public byte[] GetBytes ( System.Single v)
{
//Why is this not called?
return BitConverter.GetBytes (v);
}
But it will always go straight for the method that takes an object as parameter.
I initially tried (params object[]) as method parameters and found this behaviour to be rather obvious. But why does dynamic[] behave the same?
objects[i].GetType() reports a System.Single so what's going on here? Is what I am trying to do just not possible?
There is no reason this shouldn't work with dynamic exactly as you described. One of the primary features of the DLR is to do at runtime what would have been done at compile time if the types had been known then. For example, the following program:
public class Program
{
public static void Main(string[] args)
{
WriteItems("a string", (byte)1, 3f, new object());
}
private static void WriteItems(params dynamic[] items)
{
foreach(dynamic item in items)
{
Write(item);
}
}
private static void Write(byte b)
{
Console.WriteLine("Write byte: {0}", b);
}
private static void Write(float f)
{
Console.WriteLine("Write Single: {0}", f);
}
private static void Write(string s)
{
Console.WriteLine("Write string: {0}", s);
}
private static void Write(object o)
{
Console.WriteLine("Write object: {0}", o);
}
}
Produces the output:
Write string: a string
Write byte: 1
Write Single: 3
Write object: System.Object
Method overloading relies on knowing at compile time the types of all the arguments. Here, you can't know the argument types at compile time - because it's dynamic - so the compiler uses the lowest common type - which is object. The difference between object and dynamic is that dynamic allows late binding syntax - but that doesn't help you here.
If you want to call GetBytes for the correct types, you need to use reflection. Specifically, you want to use GetMethod to find an overload of GetBytes that matches the type of each argument, and then call it. with Invoke. Something like this(not tested):
byteList.AddRange (GetType()
.GetMethod("GetBytes", new Type[objects[i].GetType()])
.Invoke(null, new object[objects[i]]));
The dynamic type behaves like the object type. The only difference is that for dynamic the compiler does no type checking (so you can avoid compiler errors when working e.g. with COM).
What you intend, can be done anyway. But you must take the long road and do an explicit typechecking/cast in your for loop (a long but simple switch/case construct).
HTH Thomas

Is it possible to force an external class to call a specialized overload when the calling class is, itself, generic?

I am writing code that interfaces with an external API that I cannot change:
public class ExternalAPI
{
public static void Read(byte[] buffer);
public static void Read(int[] buffer);
public static void Read(float[] buffer);
public static void Read(double[] buffer);
}
It's important that I call the correct overloaded method when reading data into buffer, but once the data is read in, I will process it generically. My first pass at code that does that was:
public class Foo<T>
{
T[] buffer;
public void Stuff()
{
ExternalAPI.Foo(buffer);
}
}
C#, though, won't convert from T[] to byte[]. Is there a way to enumerate the types that T can represent explicitly? I've tried using a where T : clause, but there doesn't appear to be a way to say where T : {byte, int, float, double and nothing else ever}?
Following the advice here: Generic constraint to match numeric types, I added constraints to the generic, and also added a generic method to my simulated API that takes an object as its parameter
public class ExternalAPI
{
public static void Read(object buffer);
public static void Read(byte[] buffer);
public static void Read(int[] buffer);
public static void Read(double[] buffer);
}
public class Foo<T> where T: struct, IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable
{
T[] buffer;
public void Stuff()
{
ExternalAPI.Read(buffer);
}
}
This will compile and run happily, but the only method that is ever called is Foo(object buffer), even when T is byte. Is there a way to force methods of non-generic classes to use the most specific overload when the calling class is generic?
I've been in this situation before, and the only solution I've come up with is to test against the type of T and call the appropriate function;
public class Foo<T>
{
T[] buffer;
public void Stuff()
{
var type = typeof(T);
if (type == typeof(int[]))
{
...
}
else if (type == typeof(double[]))
{
...
}
}
}
Is there a way to force methods of non-generic classes to use the
most specific overload when the calling class is generic?
Normally, the overload resolution takes place at compile-time. Since the constraints on T, namely where T: struct, IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable, cannot point to any other overload than the one taking in object, that's the overload getting called.
If you are willing to use dynamic, the overload resolution will happen at run-time. Simply cast the argument to dynamic, like this:
public void Stuff()
{
ExternalAPI.Read((dynamic)buffer);
}
The bad thing about this is that it's slower because overload resolution has to set in when your program runs. But if T is one of byte, int, and so on, the corresponding overload with byte[], int[] etc. will be called. If T is something not supported, and if the object overload does not exist in ExternalAPI, this will fail at run-time, throwing an exception, but not until the Stuff method runs.
Another solution is to equip your Foo<T> class with a delegate to hold the correct method. It could be like:
T[] buffer;
readonly Action<T[]> readMethod;
public void Stuff()
{
readMethod(buffer);
}
//constructor
public Foo(Action<T[]> readMethod)
{
this.readMethod = readMethod;
}
But then people would have to instantiate your class like this:
new Foo<byte>(ExternalAPI.Read)
The right overload would be selected compile-time each place where people created instances of Foo<>. You could add checks in you instance constructor that readMethod is indeed a unicast delegate representing a method called Read defined by typeof(ExternalAPI).
A third solution is to make the readMethod field static, and include a static constructor that initializes readMethod. That would look ugly, but the static constructor would only run once for each type (byte, int, etc.) you used. The static constructor could throw an exception if people used a wrong T. Here's what the static constructor may look like:
static Foo()
{
if (typeof(T) == typeof(byte))
readMethod = (Action<T[]>)(Delegate)(Action<byte[]>)ExternalAPI.Read;
else if (typeof(T) == typeof(int))
readMethod = (Action<T[]>)(Delegate)(Action<int[]>)ExternalAPI.Read;
else if (typeof(T) == typeof(float))
readMethod = (Action<T[]>)(Delegate)(Action<float[]>)ExternalAPI.Read;
else if (typeof(T) == typeof(double))
readMethod = (Action<T[]>)(Delegate)(Action<double[]>)ExternalAPI.Read;
else
throw new Exception("The type parameter T can't be " + typeof(T));
}
Edit: Inspired by the first comment below, here's an attempt to make the static constructor use reflection instead:
static Foo()
{
var methInfo = typeof(ExternalAPI).GetMethod("Read", new[] { typeof(T[]), });
if (methInfo == null)
throw new Exception("ExternalAPI has no suitable method for " + typeof(T[]));
readMethod = (Action<T[]>)Delegate.CreateDelegate(typeof(Action<T[]>), methInfo);
}
I know it's a sad and redundant solution, but I think that it can't be done in a better way than this:
public void Stuff()
{
var bufferBytes = buffer as byte[];
if (bufferBytes != null)
{
ExternalAPI.Read(bufferBytes);
return;
}
var bufferInts = buffer as int[];
if (bufferInts != null)
{
ExternalAPI.Read(bufferInts);
return;
}
var bufferDoubles = buffer as double[];
if (bufferDoubles != null)
{
ExternalAPI.Read(bufferDoubles);
return;
}
ExternalAPI.Read(buffer);
}
To improve performance by casting as less as possible, reorder the checks and put the ones which are most frequently called on the top of the if/else chain. Even if the code could be made shorter by a if (buffer is byte[]) ExternalAPI.Read(buffer as byte[]); else... model, that would represent useless overhead (since you would basically be casting buffer twice).

Generics and Extension Methods Together

I need to create an extension method to array class, but this extension method must be able to accept many data types, so it also must be generic.
In the code bellow the extension method just accept byte data type. I want it to also accept ushort and uint for instance.
I believe that the best way to do that is creating a generic type here. But how can I do that using arrays?
Thanks!!!
public static class MyExtensions
{
public static int GetLastIndex(this byte[] buffer)
{
return buffer.GetUpperBound(0);
}
}
Generics in extension methods aren't really anything special, they behave just like in normal methods.
public static int GetLastIndex<T>(this T[] buffer)
{
return buffer.GetUpperBound(0);
}
As per your comment, you could do something like the following to effectively restrict the type of T (adding guard statements).
public static int GetLastIndex<T>(this T[] buffer) where T : struct
{
if (!(buffer is byte[] || buffer is ushort[] || buffer is uint[]))
throw new InvalidOperationException(
"This method does not accept the given array type.");
return buffer.GetUpperBound(0);
}
Note: As Martin Harris pointed out in a comment, you don't actually need to use generics here. The Array type from which all arrays derive will suffice.
If you want a more elegant solution, at the cost of slightly more code, you could just create overloads of the method:
public static int GetLastIndex(this byte[] buffer)
{
return GetLastIndex(buffer);
}
public static int GetLastIndex(this ushort[] buffer)
{
return GetLastIndex(buffer);
}
public static int GetLastIndex(this uint[] buffer)
{
return GetLastIndex(buffer);
}
private static int GetLastIndex(Array buffer)
{
return buffer.GetUpperBound(0);
}
public static class MyExtensions
{
public static int GetLastIndex<T>(this T[] buffer)
{
return buffer.GetUpperBound(0);
}
}
Same way you do generics in normal (non-extension) methods: Use a placeholder type name introduced in the generic syntax:
public static int GetLastIndex<TElement>(this TElement[] buffer)
#RHaguiuda
You can make constraint like
public static class MyExtensions{
public static int GetLastIndex<T>(this T[] buffer) where T: Integer
{
return buffer.GetUpperBound(0);
}}
But, type used as a constraint must be an interface, a non-sealed class or a type parameter

Categories