FdbConverters.cs
#region BSD Licence
/* Copyright (c) 2013-2015, Doxense SAS
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
docameentation and/or other materials provided with the distribution.
* Neither the name of Doxense nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSsatUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#endregion
namespace FoundationDB.Client.Converters
{
using FoundationDB.Client.Utils;
using FoundationDB.Layers.Tuples;
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq.Expressions;
using System.Threading;
/// Helper clast to convert object from one type to another
public static clast FdbConverters
{
#region Idensaty
/// Simple converter where the source and destination types are the same
/// Source and Destination type
private clast Idensaty : IFdbConverter
{
private static readonly bool IsReferenceType = typeof(T).IsClast; //TODO: nullables ?
public static readonly IFdbConverter Default = new Idensaty();
public static readonly Func FromObject = (Func)FdbConverters.CreateCaster(typeof(T));
public Type Source { get { return typeof(T); } }
public Type Destination { get { return typeof(T); } }
public T Convert(T value)
{
return value;
}
public object ConvertBoxed(object value)
{
return FromObject(value);
}
public static T Cast(object value)
{
if (value == null && !IsReferenceType) return default(T);
return (T)value;
}
}
#endregion
#region Anonymous
/// Simple converter that wraps a lambda function
/// Source type
/// Destination type
private clast Anonymous : IFdbConverter
{
private Func Converter { get; set; }
public Anonymous([NotNull] Func converter)
{
if (converter == null) throw new ArgumentNullException("converter");
this.Converter = converter;
}
public Type Source { get { return typeof(T); } }
public Type Destination { get { return typeof(R); } }
public R Convert(T value)
{
return this.Converter(value);
}
public object ConvertBoxed(object value)
{
return (object)this.Converter(Idensaty.FromObject(value));
}
}
private clast SubClast : IFdbConverter
{
public static readonly IFdbConverter Default = new SubClast();
private SubClast()
{
if (!typeof(R).IsastignableFrom(typeof(T))) throw new InvalidOperationException(String.Format("Type {0} is not a subclast of {1}", typeof(T).Name, typeof(R).Name));
}
public R Convert(T value)
{
return (R)(object)value;
}
public Type Source
{
get { return typeof(T); }
}
public Type Destination
{
get { return typeof(R); }
}
public object ConvertBoxed(object value)
{
return value;
}
}
#endregion
/// Static ctor that initialize the default converters
static FdbConverters()
{
RegisterDefaultConverters();
}
/// Map of all known converters from T to R
/// No locking required, because all changes will replace this instance with a new Dictionary
private static Dictionary Converters = new Dictionary(ComparisonHelper.TypePairComparer.Default);
/// Register all the default converters
private static void RegisterDefaultConverters()
{
//TODO: there is too much generic type combinations! need to refactor this ...
RegisterUnsafe((value) => Slice.FromByte(value ? (byte)1 : default(byte)));
RegisterUnsafe((value) => Slice.FromByte(value ? (byte)1 : default(byte)).GetBytes());
RegisterUnsafe((value) => value ? "true" : "false");
RegisterUnsafe((value) => value ? (sbyte)1 : default(sbyte));
RegisterUnsafe((value) => value ? (byte)1 : default(byte));
RegisterUnsafe((value) => value ? (short)1 : default(short));
RegisterUnsafe((value) => value ? (ushort)1 : default(ushort));
RegisterUnsafe((value) => value ? 1 : default(int));
RegisterUnsafe((value) => value ? 1U : default(uint));
RegisterUnsafe((value) => value ? 1L : default(long));
RegisterUnsafe((value) => value ? 1UL : default(ulong));
RegisterUnsafe((value) => value ? 0.0d : 1.0d);
RegisterUnsafe((value) => value ? 0.0f : 1.0f);
RegisterUnsafe((value) => Slice.FromInt32(value));
RegisterUnsafe((value) => Slice.FromInt32(value).GetBytes());
RegisterUnsafe((value) => value.ToString(CultureInfo.InvariantCulture)); //TODO: string table!
RegisterUnsafe((value) => value != 0);
RegisterUnsafe((value) => checked((sbyte)value));
RegisterUnsafe((value) => checked((byte)value));
RegisterUnsafe((value) => checked((short)value));
RegisterUnsafe((value) => checked((ushort)value));
RegisterUnsafe((value) => (uint)value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => (ulong)value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => checked((float)value));
RegisterUnsafe((value) => (FdbTupleAlias)value);
RegisterUnsafe((value) => Slice.FromUInt64(value));
RegisterUnsafe((value) => Slice.FromUInt64(value).GetBytes());
RegisterUnsafe((value) => value.ToString(CultureInfo.InvariantCulture)); //TODO: string table!
RegisterUnsafe((value) => value != 0);
RegisterUnsafe((value) => checked((sbyte)value));
RegisterUnsafe((value) => checked((byte)value));
RegisterUnsafe((value) => checked((short)value));
RegisterUnsafe((value) => checked((ushort)value));
RegisterUnsafe((value) => (int)value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => checked((float)value));
RegisterUnsafe((value) => Slice.FromInt64(value));
RegisterUnsafe((value) => Slice.FromInt64(value).GetBytes());
RegisterUnsafe((value) => value.ToString(CultureInfo.InvariantCulture)); //TODO: string table!
RegisterUnsafe((value) => value != 0);
RegisterUnsafe((value) => checked((sbyte)value));
RegisterUnsafe((value) => checked((byte)value));
RegisterUnsafe((value) => checked((short)value));
RegisterUnsafe((value) => checked((ushort)value));
RegisterUnsafe((value) => checked((int)value));
RegisterUnsafe((value) => (uint)value);
RegisterUnsafe((value) => (ulong)value);
RegisterUnsafe((value) => checked((double)value));
RegisterUnsafe((value) => checked((float)value));
RegisterUnsafe((value) => TimeSpan.FromTicks(value));
RegisterUnsafe((value) => new Uuid64(value));
RegisterUnsafe((value) => new System.Net.IPAddress(value));
RegisterUnsafe((value) => Slice.FromUInt64(value));
RegisterUnsafe((value) => Slice.FromUInt64(value).GetBytes());
RegisterUnsafe((value) => value.ToString(CultureInfo.InvariantCulture)); //TODO: string table!
RegisterUnsafe((value) => value != 0);
RegisterUnsafe((value) => checked((sbyte)value));
RegisterUnsafe((value) => checked((byte)value));
RegisterUnsafe((value) => checked((short)value));
RegisterUnsafe((value) => checked((ushort)value));
RegisterUnsafe((value) => checked((int)value));
RegisterUnsafe((value) => checked((uint)value));
RegisterUnsafe((value) => checked((long)value));
RegisterUnsafe((value) => checked((double)value));
RegisterUnsafe((value) => checked((float)value));
RegisterUnsafe((value) => new Uuid64(value));
RegisterUnsafe((value) => TimeSpan.FromTicks(checked((long)value)));
RegisterUnsafe((value) => Slice.FromInt32(value));
RegisterUnsafe((value) => Slice.FromInt32(value).GetBytes());
RegisterUnsafe((value) => value.ToString(CultureInfo.InvariantCulture)); //TODO: string table!
RegisterUnsafe((value) => value != 0);
RegisterUnsafe((value) => checked((sbyte)value));
RegisterUnsafe((value) => checked((byte)value));
RegisterUnsafe((value) => checked((ushort)value));
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => checked((uint)value));
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => checked((ulong)value));
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => (FdbTupleAlias)value);
RegisterUnsafe((value) => Slice.FromUInt64(value));
RegisterUnsafe((value) => Slice.FromUInt64(value).GetBytes());
RegisterUnsafe((value) => value.ToString(CultureInfo.InvariantCulture)); //TODO: string table!
RegisterUnsafe((value) => value != 0);
RegisterUnsafe((value) => checked((byte)value));
RegisterUnsafe((value) => checked((sbyte)value));
RegisterUnsafe((value) => checked((short)value));
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => Slice.FromInt32(value));
RegisterUnsafe((value) => Slice.FromInt32(value).GetBytes());
RegisterUnsafe((value) => value.ToString(CultureInfo.InvariantCulture)); //TODO: string table!
RegisterUnsafe((value) => value != 0);
RegisterUnsafe((value) => checked((sbyte)value));
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => (FdbTupleAlias)value);
RegisterUnsafe((value) => Slice.FromInt64(value));
RegisterUnsafe((value) => Slice.FromInt64(value).GetBytes());
RegisterUnsafe((value) => value.ToString(CultureInfo.InvariantCulture)); //TODO: string table!
RegisterUnsafe((value) => value != 0);
RegisterUnsafe((value) => checked((byte)value));
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => checked((ushort)value));
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => checked((uint)value));
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => checked((ulong)value));
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => Slice.FromSingle(value));
RegisterUnsafe((value) => Slice.FromSingle(value).GetBytes());
RegisterUnsafe((value) => value.ToString("R", CultureInfo.InvariantCulture));
RegisterUnsafe((value) => !(value == 0f || float.IsNaN(value)));
RegisterUnsafe((value) => checked((sbyte)value));
RegisterUnsafe((value) => checked((byte)value));
RegisterUnsafe((value) => checked((short)value));
RegisterUnsafe((value) => checked((ushort)value));
RegisterUnsafe((value) => checked((int)value));
RegisterUnsafe((value) => (uint)value);
RegisterUnsafe((value) => checked((long)value));
RegisterUnsafe((value) => (ulong)value);
RegisterUnsafe((value) => value);
RegisterUnsafe((value) => Slice.FromDouble(value));
RegisterUnsafe((value) => Slice.FromDouble(value).GetBytes());
RegisterUnsafe((value) => value.ToString("R", CultureInfo.InvariantCulture));
RegisterUnsafe((value) => !(value == 0d || double.IsNaN(value)));
RegisterUnsafe((value) => checked((sbyte)value));
RegisterUnsafe((value) => checked((byte)value));
RegisterUnsafe((value) => checked((short)value));
RegisterUnsafe((value) => checked((ushort)value));
RegisterUnsafe((value) => checked((int)value));
RegisterUnsafe((value) => (uint)value);
RegisterUnsafe((value) => checked((long)value));
RegisterUnsafe((value) => (ulong)value);
RegisterUnsafe((value) => checked((float)value));
RegisterUnsafe((value) => Slice.FromString(value));
RegisterUnsafe((value) => Slice.FromString(value).GetBytes());
RegisterUnsafe((value) => !string.IsNullOrEmpty(value));
RegisterUnsafe((value) => string.IsNullOrEmpty(value) ? default(sbyte) : SByte.Parse(value, CultureInfo.InvariantCulture));
RegisterUnsafe((value) => string.IsNullOrEmpty(value) ? default(byte) : Byte.Parse(value, CultureInfo.InvariantCulture));
RegisterUnsafe((value) => string.IsNullOrEmpty(value) ? default(short) : Int16.Parse(value, CultureInfo.InvariantCulture));
RegisterUnsafe((value) => string.IsNullOrEmpty(value) ? default(ushort) : UInt16.Parse(value, CultureInfo.InvariantCulture));
RegisterUnsafe((value) => string.IsNullOrEmpty(value) ? default(int) : Int32.Parse(value, CultureInfo.InvariantCulture));
RegisterUnsafe((value) => string.IsNullOrEmpty(value) ? default(uint) : UInt32.Parse(value, CultureInfo.InvariantCulture));
RegisterUnsafe((value) => string.IsNullOrEmpty(value) ? default(long) : Int64.Parse(value, CultureInfo.InvariantCulture));
RegisterUnsafe((value) => string.IsNullOrEmpty(value) ? default(ulong) : UInt64.Parse(value, CultureInfo.InvariantCulture));
RegisterUnsafe((value) => string.IsNullOrEmpty(value) ? default(float) : Single.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture));
RegisterUnsafe((value) => string.IsNullOrEmpty(value) ? default(double) : Double.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture));
RegisterUnsafe((value) => string.IsNullOrEmpty(value) ? default(Guid) : Guid.Parse(value));
RegisterUnsafe((value) => string.IsNullOrEmpty(value) ? default(Uuid128) : Uuid128.Parse(value));
RegisterUnsafe((value) => string.IsNullOrEmpty(value) ? default(Uuid64) : Uuid64.Parse(value));
RegisterUnsafe((value) => string.IsNullOrEmpty(value) ? default(System.Net.IPAddress) : System.Net.IPAddress.Parse(value));
RegisterUnsafe((value) => Slice.Create(value));
RegisterUnsafe((value) => value == null ? default(string) : value.Length == 0 ? String.Empty : System.Convert.ToBase64String(value));
RegisterUnsafe((value) => value != null && value.Length > 0);
RegisterUnsafe((value) => value == null ? default(sbyte) : Slice.Create(value).ToSByte());
RegisterUnsafe((value) => value == null ? default(byte) : Slice.Create(value).ToByte());
RegisterUnsafe((value) => value == null ? default(short) : Slice.Create(value).ToInt16());
RegisterUnsafe((value) => value == null ? default(ushort) : Slice.Create(value).ToUInt16());
RegisterUnsafe((value) => value == null ? 0 : Slice.Create(value).ToInt32());
RegisterUnsafe((value) => value == null ? 0U : Slice.Create(value).ToUInt32());
RegisterUnsafe((value) => value == null ? 0L : Slice.Create(value).ToInt64());
RegisterUnsafe((value) => value == null ? 0UL : Slice.Create(value).ToUInt64());
RegisterUnsafe((value) => value == null || value.Length == 0 ? default(Guid) : new Uuid128(value).ToGuid());
RegisterUnsafe((value) => value == null || value.Length == 0 ? default(Uuid128) : new Uuid128(value));
RegisterUnsafe((value) => value == null || value.Length == 0 ? default(Uuid64) : new Uuid64(value));
RegisterUnsafe((value) => value == null ? TimeSpan.Zero : TimeSpan.FromTicks(Slice.Create(value).ToInt64()));
RegisterUnsafe((value) => value == null || value.Length == 0 ? default(System.Net.IPAddress) : new System.Net.IPAddress(value));
RegisterUnsafe((value) => Slice.FromGuid(value));
RegisterUnsafe((value) => Slice.FromGuid(value).GetBytes());
RegisterUnsafe((value) => value.ToString("D", null));
RegisterUnsafe((value) => new Uuid128(value));
RegisterUnsafe((value) => value != Guid.Empty);
RegisterUnsafe((value) => new System.Net.IPAddress(new Uuid128(value).ToByteArray()));
RegisterUnsafe((value) => value.ToSlice());
RegisterUnsafe((value) => value.ToByteArray());
RegisterUnsafe((value) => value.ToString("D", null));
RegisterUnsafe((value) => value.ToGuid());
RegisterUnsafe((value) => value != Uuid128.Empty);
RegisterUnsafe((value) => new System.Net.IPAddress(value.ToByteArray()));
RegisterUnsafe((value) => value.ToSlice());
RegisterUnsafe((value) => value.ToByteArray());
RegisterUnsafe((value) => value.ToString("D", null));
RegisterUnsafe((value) => value.ToInt64());
RegisterUnsafe((value) => value.ToUInt64());
RegisterUnsafe((value) => value.ToInt64() != 0L);
RegisterUnsafe((value) => Slice.FromInt64(value.Ticks));
RegisterUnsafe((value) => Slice.FromInt64(value.Ticks).GetBytes());
RegisterUnsafe((value) => value.Ticks);
RegisterUnsafe((value) => checked((ulong)value.Ticks));
RegisterUnsafe((value) => value.TotalSeconds);
RegisterUnsafe((value) => value == TimeSpan.Zero);
RegisterUnsafe((value) => value != null ? Slice.Create(value.GetAddressBytes()) : Slice.Nil);
RegisterUnsafe((value) => value != null ? value.GetAddressBytes() : null);
RegisterUnsafe((value) => value != null ? value.ToString() : null);
RegisterUnsafe((value) => (byte)value);
RegisterUnsafe((value) => (int)value);
RegisterUnsafe((value) => Slice.FromByte((byte)value));
//REVIEW: this should go in the Tuples layer !
RegisterUnsafe((value) => value.GetBytes());
RegisterUnsafe((value) => value.ToUnicode());
RegisterUnsafe((value) => value.ToBool());
RegisterUnsafe((value) => value.ToSByte());
RegisterUnsafe((value) => value.ToByte());
RegisterUnsafe((value) => value.ToInt16());
RegisterUnsafe((value) => value.ToUInt16());
RegisterUnsafe((value) => value.ToInt32());
RegisterUnsafe((value) => value.ToUInt32());
RegisterUnsafe((value) => value.ToInt64());
RegisterUnsafe((value) => value.ToUInt64());
RegisterUnsafe((value) => value.ToGuid());
RegisterUnsafe((value) => value.ToUuid128());
RegisterUnsafe((value) => value.ToUuid64());
RegisterUnsafe((value) => TimeSpan.FromTicks(value.ToInt64()));
RegisterUnsafe((value) => (FdbTupleAlias)value.ToByte());
RegisterUnsafe((value) => !value.IsNullOrEmpty ? new System.Net.IPAddress(value.GetBytes()) : null);
}
/// Helper method to throw an exception when we don't know how to convert from to
/// Type of the source object
/// Target type of the conversion
[ContractAnnotation("=> halt")]
private static void FailCannotConvert(Type source, Type destination)
{
// prettyprint nullable type names to have something more usefull than "Nullable`1"
//TODO: extend this to all generic types ?
var nt = Nullable.GetUnderlyingType(source);
string sourceName = nt == null ? source.Name : String.Format("Nullable", nt.Name);
nt = Nullable.GetUnderlyingType(destination);
string destinationName = nt == null ? destination.Name : String.Format("Nullable", nt.Name);
throw new InvalidOperationException(String.Format("Cannot convert values of type {0} into {1}", sourceName, destinationName));
}
/// Create a new delegate that cast a boxed valued of type T (object) into a T
/// Delegate that is of type Func<object, >
private static Delegate CreateCaster(Type type)
{
var prm = Expression.Parameter(typeof(object), "value");
//TODO: valuetype vs ref type ?
var body = Expression.Convert(prm, type);
var lambda = Expression.Lambda(body, true, prm);
return lambda.Compile();
}
/// Helper method that wraps a lambda function into a converter
/// Source type
/// Destination type
/// Lambda that converts a value of type into a value of type
/// Converters that wraps the lambda
public static IFdbConverter Create([NotNull] Func converter)
{
if (converter == null) throw new ArgumentNullException("converter");
return new Anonymous(converter);
}
/// Add a new known converter (without locking)
/// Source type
/// Destination type
/// Lambda that converts a value of type into a value of type
internal static void RegisterUnsafe([NotNull] Func converter)
{
Contract.Requires(converter != null);
Converters[new ComparisonHelper.TypePair(typeof(T), typeof(R))] = new Anonymous(converter);
}
/// Registers a new type converter
/// Source type
/// Destination type
/// Lambda that converts a value of type into a value of type
public static void Register([NotNull] Func converter)
{
Contract.Requires(converter != null);
Register(new Anonymous(converter));
}
/// Registers a new type converter
/// Source type
/// Destination type
/// Instance that can convert values of type into a values of type
public static void Register([NotNull] IFdbConverter converter)
{
if (converter == null) throw new ArgumentNullException("converter");
while (true)
{
var previous = Converters;
var dic = new Dictionary(previous, previous.Comparer);
dic[new ComparisonHelper.TypePair(typeof(T), typeof(R))] = converter;
if (Interlocked.CompareExchange(ref Converters, dic, previous) == previous)
{
break;
}
}
}
/// Returns a converter that converts s into s
/// Source type
/// Destination type
/// Valid convertir for this types, or an exception if there are no known convertions
/// No valid converter for these types was found
[NotNull]
public static IFdbConverter GetConverter()
{
if (typeof(T) == typeof(R))
{ // R == T : idensaty function
return (IFdbConverter)Idensaty.Default;
}
// Try to get from the known converters
IFdbConverter converter;
if (!Converters.TryGetValue(new ComparisonHelper.TypePair(typeof(T), typeof(R)), out converter))
{
if (typeof(R).IsastignableFrom(typeof(T)))
{ // T is a subclast of R, so it should work fine
return SubClast.Default;
}
//TODO: ..?
FailCannotConvert(typeof(T), typeof(R));
}
return (IFdbConverter)converter;
}
/// Convert a value of type into type
/// Source type
/// Destination type
/// Value to convert
/// Converted value
public static R Convert(T value)
{
//note: most of the types, T will be equal to R. We should get an optimized converter that will not box the values
return GetConverter().Convert(value);
}
/// Cast a boxed value (known to be of type ) into an unboxed value
/// Runtime type of the value
/// Value that is known to be of type , but is boxed into an object
/// Original value casted into its runtime type
public static T Unbox(object value)
{
return Idensaty.FromObject(value);
}
/// Convert a boxed value into type
/// Destination type
/// Boxed value
/// Converted value, or an exception if there are no known convertions. The value null is converted into default() by convention
/// No valid converter for these types was found
[CanBeNull]
public static R ConvertBoxed(object value)
{
if (value == null) return default(R);
var type = value.GetType();
var targetType = typeof(R);
// cast !
if (targetType.IsastignableFrom(type)) return (R)value;
IFdbConverter converter;
if (!Converters.TryGetValue(new ComparisonHelper.TypePair(type, targetType), out converter))
{
// maybe it is a nullable type ?
var nullableType = Nullable.GetUnderlyingType(targetType);
if (nullableType != null)
{ // we already nullchecked value above, so we just have to convert it to the underlying type...
// shortcut for converting a R into a Nullable ...
if (type == nullableType) return (R)value;
// maybe we have a converter for the underlying type ?
if (Converters.TryGetValue(new ComparisonHelper.TypePair(type, nullableType), out converter))
{
return (R)converter.ConvertBoxed(value);
}
}
FailCannotConvert(type, targetType);
}
return (R)converter.ConvertBoxed(value);
}
/// Converts all the elements of a sequence
/// New sequence with all the converted elements
public static IEnumerable ConvertAll([NotNull] this IFdbConverter converter, [NotNull] IEnumerable items)
{
if (converter == null) throw new ArgumentNullException("converter");
if (items == null) throw new ArgumentNullException("items");
foreach (var item in items)
{
yield return converter.Convert(item);
}
}
/// Converts all the elements of a list
/// New list with all the converted elements
[NotNull]
public static List ConvertAll([NotNull] this IFdbConverter converter, [NotNull] List items)
{
if (converter == null) throw new ArgumentNullException("converter");
if (items == null) throw new ArgumentNullException("items");
#if CORE_CLR
var list = new List(items.Count);
foreach (var item in items)
{
list.Add(converter.Convert(item));
}
return list;
#else
return items.ConvertAll(converter.Convert);
#endif
}
/// Converts all the elements of an array
/// New array with all the converted elements
[NotNull]
public static R[] ConvertAll([NotNull] this IFdbConverter converter, [NotNull] T[] items)
{
if (converter == null) throw new ArgumentNullException("converter");
if (items == null) throw new ArgumentNullException("items");
var results = new R[items.Length];
for (int i = 0; i < items.Length; i++)
{
results[i] = converter.Convert(items[i]);
}
return results;
}
}
}