Reputation: 459
I need to design a data structure that holds different types of values (doubles, strings, datetimes, etc.). The list of types is dynamically created by user. Based on that list another list of values should be created. Then this "record" of values is to be sent by WCF and stored in dynamically created db table. I'm starting with desiging this solution in c#. My current status is shown below. I'm not satisfied with my present solution, especially with factory and enums. Is there better way to do the things right?
Enum for my types:
public enum ValueType { Decimal, String, Boolean };
then interface:
public interface IValueType
{
object Data { get; }
string ToString();
ValueType? Type { get; }
}
base class:
public abstract class ValueType<T> : IValueType
{
protected T _Value;
public ValueType(T value)
{
_Value = value;
}
public object Data
{
get { return _Value; }
}
public ValueType? Type
{
get { return null; }
}
public T Value { get; private set; }
public override string ToString()
{
return _Value.ToString();
}
}
one of implementation:
public class DecimalValueType : ValueType<decimal>
{
public DecimalValueType( decimal val ) : base(val)
{}
public DecimalValueType(double val) : base((decimal)val)
{}
public DecimalValueType(int val) : base((decimal)val)
{}
}
then factory:
public static class ValueTypeFactory
{
private static Dictionary<ValueType, Type> dictValueType = new Dictionary<ValueType, Type>()
{
{ ValueType.Decimal, typeof(DecimalValueType) },
{ ValueType.String, typeof(StringValueType) },
{ ValueType.Boolean, typeof(BooleansValueType) }
};
private static Dictionary<Type, Type> dictSimple = new Dictionary<Type, Type>()
{
{ typeof(decimal), typeof(DecimalValueType) },
{ typeof(double), typeof(DecimalValueType) },
{ typeof(int), typeof(DecimalValueType) },
{ typeof(string), typeof(StringValueType) },
{ typeof(bool), typeof(BooleansValueType) }
};
public static IValueType MakeByValueType(ValueType type, params object[] initValues)
{
IValueType retObject = null;
if (dictValueType.ContainsKey(type) )
{
Type t = dictValueType[type];
retObject = (IValueType)Activator.CreateInstance(t,initValues);
}
return retObject;
}
public static IValueType MakeByType(params object[] initValues)
{
IValueType retObject = null;
if ( initValues.Length > 0 )
{
Type type = initValues[0].GetType();
if (dictSimple.ContainsKey(type))
{
Type t = dictSimple[type];
retObject = (IValueType)Activator.CreateInstance(t, initValues);
}
}
return retObject;
}
}
sample use:
List<IValueType> lista = new List<IValueType>();
lista.Add(new DecimalValueType(12));
lista.Add(new StringValueType("Test"));
lista.Add(new BooleansValueType(true));
lista.Add(ValueTypeFactory.MakeByValueType(ValueType.Decimal, 10.1));
lista.Add(ValueTypeFactory.MakeByType(5.12));
lista.Add(ValueTypeFactory.MakeByType("Test2"));
I would be happy with any advice.
Upvotes: 2
Views: 1661
Reputation: 2608
Here is a simpler solution that covers the usages in your post and avoids the ValueType
subclass noise:
public abstract class ValueType
{
public enum Types { Decimal, String, Boolean };
public abstract object Data { get; }
public abstract Types Type { get; }
private ValueType() {}
protected class TypedValueType<T> : ValueType
{
private Types type;
public TypedValueType(T value, Types type) : base()
{
this.Value = value;
this.type = type;
}
public override object Data { get { return this.Value; } }
public override Types Type { get { return this.type; } }
public T Value { get; private set; }
public override string ToString()
{
return this.Value.ToString();
}
}
public static implicit operator ValueType(decimal value) { return new TypedValueType<decimal>(value, Types.Decimal); }
public static implicit operator ValueType(double value) { return new TypedValueType<decimal>((decimal)value, Types.Decimal); }
public static implicit operator ValueType(int value) { return new TypedValueType<decimal>((decimal)value, Types.Decimal); }
public static implicit operator ValueType(string value) { return new TypedValueType<string>(value, Types.String); }
public static implicit operator ValueType(bool value) { return new TypedValueType<bool>(value, Types.Boolean); }
}
Sample usage:
public class Demo
{
public static void Main()
{
List<ValueType> lista = new List<ValueType>();
lista.Add(1);
lista.Add("Test");
lista.Add(true);
lista.Add(10.1);
lista.Add(5.12);
lista.Add("Test2");
foreach(var value in lista) Console.WriteLine(value.Data + " - " + value.Type.ToString());
Console.ReadKey();
}
}
Since it appears that you are wanting to restrict the types of values that can be contained, the nested TypedValueType
class is marked protected and the ValueType
constructor is marked private. Implicit operators are used to provide the "factory" logic for producing the appropriate typed TypeValueType
subclasses for the values that are to be casted.
Here is the output from executing this as a console app:
1 - Decimal
Test - String
True - Boolean
10.1 - Decimal
5.12 - Decimal
Test2 - String
Upvotes: 1