Skip to content

Commit

Permalink
Added EnumConverterFactory and CollectionConverterFactory. Changed fa…
Browse files Browse the repository at this point in the history
…ctory creation to give back whether it should be added to the cache.
  • Loading branch information
JoshClose committed Oct 6, 2022
1 parent 1dbe3d3 commit 5aec4ba
Show file tree
Hide file tree
Showing 16 changed files with 323 additions and 164 deletions.
175 changes: 175 additions & 0 deletions src/CsvHelper/TypeConversion/CollectionConverterFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
// Copyright 2009-2022 Josh Close
// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0.
// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0.
// https://github.com/JoshClose/CsvHelper
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace CsvHelper.TypeConversion
{
/// <inheritdoc />
public class CollectionConverterFactory : ITypeConverterFactory
{
private int dictionaryTypeHashCode = typeof(IDictionary).GetHashCode();
private List<int> enumerableTypeHashCodes = new List<int>
{
typeof(IList).GetHashCode(),
typeof(ICollection).GetHashCode(),
typeof(IEnumerable).GetHashCode(),
};

/// <inheritdoc />
public bool CanCreate(Type type)
{
switch (type)
{
case IList:
case IDictionary:
case ICollection:
case IEnumerable:
return true;
}

if (type.IsArray)
{
// ArrayConverter
return true;
}

if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>))
{
// IDictionaryGenericConverter
return true;
}

if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>))
{
// IDictionaryGenericConverter
return true;
}

if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
{
// CollectionGenericConverter
return true;
}

if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Collection<>))
{
// CollectionGenericConverter
return true;
}

if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IList<>))
{
// IEnumerableGenericConverter
return true;
}

if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(ICollection<>))
{
// IEnumerableGenericConverter
return true;
}

if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
// IEnumerableGenericConverter
return true;
}

// A specific IEnumerable converter doesn't exist.
if (typeof(IEnumerable).IsAssignableFrom(type))
{
// EnumerableConverter
return true;
}

return false;
}

/// <inheritdoc />
public bool Create(Type type, TypeConverterCache cache, out ITypeConverter typeConverter)
{
var typeHashCode = type.GetHashCode();

if (typeHashCode == dictionaryTypeHashCode)
{
typeConverter = new IDictionaryConverter();
return true;
}

if (enumerableTypeHashCodes.Contains(typeHashCode))
{
typeConverter = new IEnumerableConverter();
return true;
}

if (type.IsArray)
{
typeConverter = new ArrayConverter();
return true;
}

var isGenericType = type.GetTypeInfo().IsGenericType;
var genericTypeDefinition = type.GetGenericTypeDefinition();

if (isGenericType && genericTypeDefinition == typeof(Dictionary<,>))
{
typeConverter = new IDictionaryGenericConverter();
return true;
}

if (isGenericType && genericTypeDefinition == typeof(IDictionary<,>))
{
typeConverter = new IDictionaryGenericConverter();
return true;
}

if (isGenericType && genericTypeDefinition == typeof(List<>))
{
typeConverter = new CollectionGenericConverter();
return true;
}

if (isGenericType && genericTypeDefinition == typeof(Collection<>))
{
typeConverter = new CollectionGenericConverter();
return true;
}

if (isGenericType && genericTypeDefinition == typeof(IList<>))
{
typeConverter = new IEnumerableGenericConverter();
return true;
}

if (isGenericType && genericTypeDefinition == typeof(ICollection<>))
{
typeConverter = new IEnumerableGenericConverter();
return true;
}

if (isGenericType && genericTypeDefinition == typeof(IEnumerable<>))
{
typeConverter = new IEnumerableGenericConverter();
return true;
}

// A specific IEnumerable converter doesn't exist.
if (typeof(IEnumerable).IsAssignableFrom(type))
{
typeConverter = new EnumerableConverter();
return true;
}

throw new InvalidOperationException($"Cannot create collection converter for type '{type.FullName}'.");
}
}
}
35 changes: 35 additions & 0 deletions src/CsvHelper/TypeConversion/EnumConverterFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2009-2022 Josh Close
// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0.
// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0.
// https://github.com/JoshClose/CsvHelper
using System;

namespace CsvHelper.TypeConversion
{
/// <inheritdoc />
public class EnumConverterFactory : ITypeConverterFactory
{
/// <inheritdoc />
public bool CanCreate(Type type)
{
return typeof(Enum).IsAssignableFrom(type);
}

/// <inheritdoc />
public bool Create(Type type, TypeConverterCache cache, out ITypeConverter typeConverter)
{
if (cache.Contains(typeof(Enum)))
{
// If the user has registered a converter for the generic Enum type,
// that converter will be used as a default for all enums.
typeConverter = cache.GetConverter<Enum>();

return false;
}

typeConverter = new EnumConverter(type);

return true;
}
}
}
26 changes: 16 additions & 10 deletions src/CsvHelper/TypeConversion/ITypeConverterFactory.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
using System;
// Copyright 2009-2022 Josh Close
// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0.
// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0.
// https://github.com/JoshClose/CsvHelper
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace CsvHelper.TypeConversion
Expand All @@ -10,18 +15,19 @@ namespace CsvHelper.TypeConversion
public interface ITypeConverterFactory
{
/// <summary>
/// Checks whether the type is handled by this <see cref="ITypeConverterFactory"/>.
/// Determines if the factory can create a type converter for the given type.
/// </summary>
/// <param name="type"><see cref="System.Type"/> to be checked</param>
/// <returns>Whether the type is handled by this <see cref="ITypeConverterFactory"/></returns>
bool Handles(Type type);
/// <param name="type">The <see cref="Type"/> to be checked</param>
/// <returns><c>true</c> if the factory can create the type, otherwise <c>false</c>.</returns>
bool CanCreate(Type type);

/// <summary>
/// Produces <see cref="ITypeConverter"/> for the specified <see cref="System.Type"/>.
/// Creates a type converter for the given type and assigns it to the given out typeConverter parameter.
/// </summary>
/// <param name="type"><see cref="System.Type"/> we want <see cref="ITypeConverter"/> for</param>
/// <param name="typeConverterCache"><see cref="TypeConverterCache"/> that is used for retrieving already exising type converters that are used to build the new one</param>
/// <returns>Created <see cref="ITypeConverter"/> for the specified <see cref="System.Type"/></returns>
ITypeConverter CreateTypeConverter(Type type, TypeConverterCache typeConverterCache);
/// <param name="type">The type to create the converter for.</param>
/// <param name="cache">The type converter cache.</param>
/// <param name="typeConverter">The parameter to set the converter to.</param>
/// <returns><c>true</c> if the converter should be added to the cache, otherwise <c>false</c>.</returns>
bool Create(Type type, TypeConverterCache cache, out ITypeConverter typeConverter);
}
}
33 changes: 14 additions & 19 deletions src/CsvHelper/TypeConversion/NullableConverterFactory.cs
Original file line number Diff line number Diff line change
@@ -1,33 +1,28 @@
using System;
// Copyright 2009-2022 Josh Close
// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0.
// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0.
// https://github.com/JoshClose/CsvHelper
using System;
using System.Collections.Generic;
using System.Linq;

namespace CsvHelper.TypeConversion
{
/// <summary>
/// Converter factory for nullable types
/// </summary>
/// <inheritdoc />
public class NullableConverterFactory : ITypeConverterFactory
{
/// <summary>
/// Produces <see cref="ITypeConverter"/> for the specified <see cref="System.Type"/>.
/// </summary>
/// <param name="type"><see cref="System.Type"/> we want <see cref="ITypeConverter"/> for</param>
/// <param name="typeConverterCache"><see cref="TypeConverterCache"/> that is used for retrieving already exising type converters that are used to build the new one</param>
/// <returns>Created <see cref="ITypeConverter"/> for the specified <see cref="System.Type"/></returns>
public ITypeConverter CreateTypeConverter(Type type, TypeConverterCache typeConverterCache)
/// <inheritdoc />
public bool CanCreate(Type type)
{
return new NullableConverter(type, typeConverterCache);
return (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)));
}

/// <summary>
/// Checks whether the type is handled by <see cref="NullableConverterFactory"/>.
/// </summary>
/// <param name="type"><see cref="System.Type"/> to be checked</param>
/// <returns>Whether the type is handled by <see cref="NullableConverterFactory"/></returns>
public bool Handles(Type type)
/// <inheritdoc />
public bool Create(Type type, TypeConverterCache cache, out ITypeConverter typeConverter)
{
return (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)));
typeConverter = new NullableConverter(type, cache);

return true;
}
}
}
Loading

0 comments on commit 5aec4ba

Please sign in to comment.