First, here is why this question is not a duplicate:
I know that multiple questions about converting one enum
to another have been asked on SO, I even answered one of them myself, but all the questions I've found on this topic had some way of comparing the different enum values (whether by name or by value). In my particular case, I don't know the values, and the names don't match.
As a part of a GitHub project I'm working on, called ADONETHelper, that's designed to minimize code repetition when working with Ado.Net, I came face to face with the need to translate values between unrelated enums. This is to allow the same code to work with OleDb, Odbc, and SqlClient (and hopefully in the future OracleClient and MySqlClient as well).
What I'm trying to do is create a unification of different enums - specifically - enums that describe sql parameters data types.
Currntly, I am supporting 4 enums -
System.Data.DbType
,
System.Data.SqlClient.SqlDbType
,
System.Data.OleDb.OleDbType
,
System.Data.Odbc.OdbcType
but if I want to add support for OracleClient or MySqlClient, I'll have to work pretty hard to add System.Data.OracleClient.OracleType
Or MySql.Data.MySqlClient.MySqlDbType
.
So I'm looking for a more elegant way of doing this then I came up with.
Here is my current code (It works great, but as I wrote, it's hard to add support for new enums):
So first, I have defined my own enum called ADONETType
. It has entries such as Boolean
, Byte
, Binary
, Char
etc'.
Then I've created a static class called DBTypeConverter
to provide extension methods to this enum, so that it's value could be converted to the other enums.
This is what this class looks like:
internal static class DBTypeConverter
{
#region private members
private static List<DbTypeMap> _Map;
#endregion private members
#region static constructor
static DBTypeConverter()
{
_Map = new List<DbTypeMap>()
{
new DbTypeMap(ADONETType.Boolean, DbType.Boolean, SqlDbType.Bit, OleDbType.Boolean, OdbcType.Bit),
new DbTypeMap(ADONETType.Byte, DbType.Byte, SqlDbType.TinyInt, OleDbType.UnsignedTinyInt , OdbcType.TinyInt),
new DbTypeMap(ADONETType.Binary, DbType.Binary, SqlDbType.Binary, OleDbType.Binary, OdbcType.Binary),
// ... more of the same here ...
new DbTypeMap(ADONETType.Xml, DbType.Xml, SqlDbType.Xml, null, null)
};
}
#endregion static constructor
#region methods
internal static DbType ToDbType(this ADONETType type)
{
return type.ConvertTo<DbType>();
}
internal static SqlDbType ToSqlType(this ADONETType type)
{
return type.ConvertTo<SqlDbType>();
}
internal static OleDbType ToOleDbType(this ADONETType type)
{
return type.ConvertTo<OleDbType>();
}
internal static OdbcType ToOdbcType(this ADONETType type)
{
return type.ConvertTo<OdbcType>();
}
private static dynamic ConvertTo<T>(this ADONETType type)
{
var returnValue = _Map.First(m => m.ADONETType == type).GetValueByType(typeof(T));
if(returnValue != null)
{
return returnValue;
}
throw new NotSupportedException(string.Format("ADONETType {0} is not supported for {1}", type, typeof(T)));
}
#endregion methods
#region private struct
private struct DbTypeMap
{
#region ctor
public DbTypeMap(ADONETType adonetType, DbType? dbType, SqlDbType? sqlDbType, OleDbType? oleDbType, OdbcType? odbcType)
: this()
{
ADONETType = adonetType;
DbType = dbType;
SqlDbType = sqlDbType;
OleDbType = oleDbType;
OdbcType = odbcType;
}
#endregion ctor
#region properties
internal ADONETType ADONETType { get; private set; }
internal DbType? DbType { get; private set; }
internal SqlDbType? SqlDbType { get; private set; }
internal OleDbType? OleDbType { get; private set; }
internal OdbcType? OdbcType { get; private set; }
#endregion properties
#region methods
internal dynamic GetValueByType(Type type)
{
if (type == typeof(ADONETType))
{
return this.ADONETType;
}
if(type == typeof(DbType))
{
return this.DbType;
}
if (type == typeof(SqlDbType))
{
return this.SqlDbType;
}
if (type == typeof(OleDbType))
{
return this.OleDbType;
}
if (type == typeof(OdbcType))
{
return this.OdbcType;
}
return null;
}
#endregion methods
}
#endregion private struct
}
Now, as you can see, In order to provide support for, say, OracleClient, I'll have to do the following:
- Add a property for
OracleType
in theDbTypeMap
private struct. - Change the
DbTypeMap
constructor to accept also the oracle type. - Add another case to the switch in
GetValueByType
method. - Add the oracle type to the static constructor of
DBTypeConverter
. - Add a method (
internal static OracleType ToOracleType(this ADONETType type)
) toDBTypeConverter
.
Obvoisuly, this is a lot of work and I would much rather find another way to unify these enums, so adding support to new clients will be easier.
This is when your experties come in to play.