C# 如何在一个列表中为不同类型的值设计工厂模式?
我需要设计一个包含不同类型值(双精度、字符串、日期时间等)的数据结构。类型列表由用户动态创建。应根据该列表创建另一个值列表。 然后这个值的“记录”将由WCF发送并存储在动态创建的db表中。我从用c#设计这个解决方案开始。我的当前状态如下所示。我对目前的解决方案不满意,尤其是工厂和枚举。有没有更好的方法把事情做好 我的类型的枚举:C# 如何在一个列表中为不同类型的值设计工厂模式?,c#,generics,design-patterns,collections,factory,C#,Generics,Design Patterns,Collections,Factory,我需要设计一个包含不同类型值(双精度、字符串、日期时间等)的数据结构。类型列表由用户动态创建。应根据该列表创建另一个值列表。 然后这个值的“记录”将由WCF发送并存储在动态创建的db表中。我从用c#设计这个解决方案开始。我的当前状态如下所示。我对目前的解决方案不满意,尤其是工厂和枚举。有没有更好的方法把事情做好 我的类型的枚举: public enum ValueType { Decimal, String, Boolean }; 然后接口: public interface IValueTy
public enum ValueType { Decimal, String, Boolean };
然后接口:
public interface IValueType
{
object Data { get; }
string ToString();
ValueType? Type { get; }
}
基类:
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();
}
}
公共抽象类ValueType:IValueType
{
保护T_值;
公共价值类型(T值)
{
_价值=价值;
}
公共对象数据
{
获取{返回_值;}
}
公共价值类型
{
获取{return null;}
}
公共T值{get;私有集;}
公共重写字符串ToString()
{
返回_Value.ToString();
}
}
实施之一:
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)
{}
}
公共类DecimalValueType:ValueType
{
公共小数值类型(十进制val):基数(val)
{}
公共小数值类型(双val):基数((十进制)val)
{}
公共小数值类型(int val):基数((十进制)val)
{}
}
然后工厂:
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;
}
}
公共静态类ValueTypeFactory
{
私有静态字典dictValueType=新字典()
{
{ValueType.Decimal,typeof(DecimalValueType)},
{ValueType.String,typeof(StringValueType)},
{ValueType.Boolean,typeof(BooleansValueType)}
};
私有静态字典dictSimple=newdictionary()
{
{typeof(decimal),typeof(DecimalValueType)},
{typeof(double),typeof(DecimalValueType)},
{typeof(int),typeof(DecimalValueType)},
{typeof(string),typeof(StringValueType)},
{typeof(bool),typeof(BooleansValueType)}
};
公共静态IValueType MakeByValueType(ValueType类型,参数对象[]初始值)
{
IValueType retObject=null;
if(dictValueType.ContainsKey(类型))
{
类型t=dictValueType[类型];
retObject=(IValueType)Activator.CreateInstance(t,initValues);
}
返回对象;
}
公共静态IValueType MakeByType(参数对象[]初始值)
{
IValueType retObject=null;
如果(initValues.Length>0)
{
类型Type=initValues[0]。GetType();
if(dictSimple.ContainsKey(类型))
{
类型t=简单[类型];
retObject=(IValueType)Activator.CreateInstance(t,initValues);
}
}
返回对象;
}
}
样本使用:
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"));
List lista=新列表();
添加(新的小数点类型(12));
添加(新的StringValueType(“测试”));
Add(新的BooleansValueType(true));
添加(ValueTypeFactory.MakeByValueType(ValueType.Decimal,10.1));
添加(ValueTypeFactory.MakeByType(5.12));
Add(ValueTypeFactory.MakeByType(“Test2”));
我很乐意接受任何建议。这里有一个更简单的解决方案,它涵盖了您文章中的用法,并避免了
ValueType
子类噪音:
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); }
}
我有一种“过度设计”的感觉。最有可能的情况是,您必须多解释一点您的用例(以及为什么您首先要这么做)。例如,这在什么方面比列表和白名单更好呢?在桌面应用程序中,我收到了200多个实时参数的记录,其中有一些时间步长。我的目标是在这个桌面应用程序(用mfc编写)和web应用程序(连接到sql数据库)之间架起一座桥梁。我决定使用wcfapi。web应用程序的管理员创建他希望在db中包含的参数列表。因此,我必须根据create表在其类型中列出这些参数,并向WCF服务发送一个适当的值列表。
IValueType
接口看起来没用。我只需要一个带有受保护构造函数的公共抽象类ValueType
。然后,如果客户机代码只希望自动推断类型,而我不会实现MakeByValueType
操作,那么我将使用依赖于反射的工厂来查找具体的ValueType
实现。这与新的ConcreteValueType(…)
相同。我认为需要使用IValueType将所有派生类放到一个集合中—我不能将ValueType的泛型版本(使用不同的T)添加到一个集合中。关于枚举-用户必须有选择权(一些不同类型的列表)选择所需的参数类型。所以我在choosed类型和由静态方法MakeByValueType创建的IValueType实例之间建立了连接。我错了吗?很好的解决方案!非常干净优雅。隐式运算符的良好使用。非常感谢你!
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();
}
}
1 - Decimal
Test - String
True - Boolean
10.1 - Decimal
5.12 - Decimal
Test2 - String