I have a decode method, which decodes Json and returns a certain type of class thats passed in:
/// Service for parsing and serializing Json
public protocol JsonService
{
/// Decodes a top-level value of the given type from the given JSON representation.
///
/// - parameter type: The type of the value to decode.
/// - parameter data: The data to decode from.
/// - returns: A value of the requested type.
/// - throws: `DecodingError.dataCorrupted` if values requested from the payload are corrupted, or if the given data is not valid JSON.
/// - throws: An error if any value throws an error during decoding.
#if os(iOS) || os(OSX)
func decode<T>(_ type: T.Type, from bytes: Bytes) throws -> T where T : Decodable
#endif
#if NET
func decode<T>(_ type: System.Type, from bytes: Bytes) throws -> T
#endif
#if ANDROID
func decode<T>(_ type: java.lang.Class<T>, from bytes: Bytes) throws -> T
#endif
}
This is used like:
let myObj: MyObject = jsonService.decode( MyObject.self, someJsonBytes)
As you can see I have to specialise the method signature for XCode, Cooper/Java & Echoes/.Net, as T.Type isnt valid in Silver.
This works well in XCode & Cooper/Java, but in Echoes/.Net I have problems because System.Type is not generic, like the other two.
The only way I can get this to work in Echose/.Net is to call like jsonService.decode<MyObject>( MyObject.self, someJsonBytes)
Which would be ok, except that XCode hates this, and gives an error at this syntax:
So - looking for ideas or tricks how I can get the .Net/Echoes version working the same as the others, where the generic return type is specified by the type passed as the first param.
I guess worst case is I have to return Any, and force cast everywhere in client code. But ugly!
Best I can do that works across platform with one syntax is:
Cooper
class Decoder<T>
{
var c: Class<T>
init(_ type: Class<T>)
{
self.c = type
}
func decode() -> T
{
print(c)
return c.newInstance() as! T
}
}
class MyClass
{}
let my: MyClass = Decoder<MyClass>(MyClass.self).decode()
print(my)
Echoes
class Decoder<T>
{
var c: System.Type
init(_ type: System.Type)
{
self.c = type
}
func decode() -> T
{
print(c)
return c.GetConstructors()[0].Invoke([]) as! T
}
}
class MyClass
{}
let my: MyClass = Decoder<MyClass>(MyClass.self).decode()
print(my)
Which is ok I guess except for the verbosesness of the call: Decoder<MyClass>(MyClass.self).decode()
This sounds like something we need to add proper support for.
As a workaround, if you use Elements for all platforms and use Elements RTL, there’s a cross-platform Type type you can use (similar to System.Type, except it is mapped properly on each platform, so you don’t need to ifdef).