【分享】将页面的数据转化为实体类,实现的不优雅,也请大虾帮改改。谢谢~

NqIceCoffee 2008-12-16 01:30:37
public static class ModelBuilder
{
public static TModel Build<TModel>(NameValueCollection itemCollection) where TModel : new()
{
Type type = typeof(TModel);
TModel model = new TModel();
foreach (string name in itemCollection.AllKeys)
{
PropertyInfo property = type.GetProperty(name);
if (property != null)
{
object input;
Type t = property.PropertyType;
bool flag = TryParseValue(itemCollection[name], t, out input);
if (flag)
property.SetValue(model, input, null);
}
}
return model;
}

//1.感觉此部分不够优雅,还请大虾给出更好的实现方法
//2.仅实现了部分.NET基础类型的转换
private static bool TryParseValue(string input, Type type, out object result)
{
result = string.Empty;
if (string.IsNullOrEmpty(input)) return false;

bool flag = false;
string typeName = type.FullName;
switch (typeName)
{
case "System.String" :
result = input;
return true;
case "System.Int16" :
Int16 r1;
flag = Int16.TryParse(input, out r1);
result = r1;
return flag;
case "System.Int32" :
int r2;
flag = int.TryParse(input, out r2);
result = r2;
return flag;
case "System.Int64" :
Int64 r3;
flag = Int64.TryParse(input, out r3);
result = r3;
return flag;
case "System.DateTime" :
DateTime r4;
flag = DateTime.TryParse(input, out r4);
result = r4;
return flag;
case "System.Boolean" :
if (input == "1" || string.Compare(input, "true", true) == 0)
result = true;
else
result = false;
return true;
default :
return false;
}
}
}



实体对象

public class TestModel
{
public string Name { get; set; }
public int Count { get; set; }
public bool IsLimit { get; set; }
public DateTime Time { get; set; }
}


调用代码
if (Request.HttpMethod == "POST")
{
TestModel test = ModelBuilder.Build<TestModel>(Request.Form);
Response.Write("Done");
}



页面代码
<form method="post">
<input type="text" name="Name" />
<input type="text" name="Count" />
<input type="text" name="IsLimit" />
<input type="text" name="Time" />
<input type=submit input="提交" />
</form>


欢迎大家拍砖~!
...全文
311 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
u
NqIceCoffee 2008-12-18
  • 打赏
  • 举报
回复
按照SP1234的思路修改后

结果却不是所期望的那样,很奇怪。

修改后的代码==》

public static class ModelBuilder
{
private static Dictionary<string, PropertyInfo> PropertyDictionary = new Dictionary<string, PropertyInfo>();

public static TModel Build<TModel>(NameValueCollection itemCollection, string namePrefix) where TModel : new()
{
TModel model = new TModel();
Type modelType = typeof(TModel);
foreach (string name in itemCollection.AllKeys)
{
if (!name.StartsWith(namePrefix)) continue;

string value = itemCollection[name];
if (string.IsNullOrEmpty(value)) continue;

string propName = name;
if (!string.IsNullOrEmpty(namePrefix))
propName = name.Substring(namePrefix.Length);

PropertyInfo prop = GetPropertyInfo(modelType, propName); //modelType.GetProperty(propName);
if (prop == null) continue;

bool flag = false;
object objValue = null;
Type propType = prop.PropertyType;

try
{
if (propType.IsEnum)
objValue = Enum.Parse(propType, value, true);
else
objValue = Convert.ChangeType(value, propType);

flag = true;
}
catch { }

if (flag)
prop.SetValue(model, objValue, null);
}
return model;
}

private static PropertyInfo GetPropertyInfo(Type modelType, string propertyName)
{
PropertyInfo property = null;
string propertyFullName = string.Format("{0}.{1}", modelType.FullName, propertyName);

if (PropertyDictionary.TryGetValue(propertyFullName, out property))
return property;

property = modelType.GetProperty(propertyName);
if (property != null)
{
lock (PropertyDictionary)
{
PropertyDictionary.Add(propertyFullName, property);
}
}
return property;
}
}



测试的环境和条件都和22楼的代码一样

但这个用缓存的性能反而下降了,10W次的消耗的时间在7850毫秒左右

比不使用缓存的性能还低,费解。。。。。
NqIceCoffee 2008-12-17
  • 打赏
  • 举报
回复

TypeDescriptor.GetConverter(property.PropertyType).ConvertFrom(properties.Get(str))

Convert.ChangeType(value, propertyType);

//这俩都是类型转换,有啥区别没?或者用哪个性能更好?
//我偷偷测试去
fellowcheng 2008-12-17
  • 打赏
  • 举报
回复
TypeDescriptor.GetConverter方法还是比较有用的

 public void SetProerties(NameValueCollection properties)
{
foreach (string str in properties)
{
PropertyInfo property = base.GetType().GetProperty(str);
if (property != null)
{
property.SetValue(this, TypeDescriptor.GetConverter(property.PropertyType).ConvertFrom(properties.Get(str)), null);
}
}
}
NqIceCoffee 2008-12-17
  • 打赏
  • 举报
回复
恩,感谢,感谢,SP1234

一直在找反射哪个地方性能比较差。没想到你就说出来了,呵呵,再次感谢。

一会优化下后,在发一下性能测试报告。

呵呵
  • 打赏
  • 举报
回复
实现要初始化一个PropDictionary --> 事先要初始化一个 static <string,PropertyInfo> PropDictionary=new <string,PropertyInfo>();
  • 打赏
  • 举报
回复
你试试看,如果减少GetProperty操作次数,测试结果是不是差别更小。
  • 打赏
  • 举报
回复
没有仔细开你的代码。不过,

PropertyInfo property = type.GetProperty(name);

这条代码通常可以优化为仅仅执行一次,然后就放入一个static的Dictionary<string,PropInfo>类型的集合中。

例如可以把这行写为:

PropertyInfo property = GetPropertyInfo(type,name);

然后这个GetPropertyInfo方法例如可以设计为:

public static GetPropertyInfo(Type type,string name)
{
PropertyInfo prop;
string key=type.Namespace+"."+type.Name+."+name;
if(!PropDictionary.TryGetValue(key,out prop)) //实现要初始化一个PropDictionary
{
prop=type.GetProperty(name);
PropDictionary.Add(key,prop);
}
return prop;
}
NqIceCoffee 2008-12-17
  • 打赏
  • 举报
回复
公布最后完整版
public static class ModelBuilder
{
public static TModel Build<TModel>(NameValueCollection itemCollection, string namePrefix) where TModel : new()
{
TModel model = new TModel();
Type modelType = typeof(TModel);
foreach (string name in itemCollection.AllKeys)
{
string value = itemCollection[name];
if (string.IsNullOrEmpty(value)) continue;

string propertyName = name;
if (!string.IsNullOrEmpty(namePrefix))
propertyName = name.Substring(namePrefix.Length);

PropertyInfo property = modelType.GetProperty(propertyName);
if (property == null) continue;

bool flag = false;
object objValue = null;
Type propertyType = property.PropertyType;

try
{
if (propertyType.IsEnum)
objValue = Enum.Parse(propertyType, value, true);
else
objValue = Convert.ChangeType(value, propertyType);

flag = true;
}
catch { }

if (flag)
property.SetValue(model, objValue, null);
}
return model;
}
}


下面是测试性能

1.实体对象
    public class TestModel
{
public string Name { get; set; }
public int Count { get; set; }
public bool IsLimit { get; set; }
public DateTime Time { get; set; }
public ModelType Type { get; set; }
}

public enum ModelType
{
Table = 1,
View = 2
}


2.测试代码

if (Request.HttpMethod == "POST")
{
DateTime sTime = DateTime.Now;
for (int i = 0; i < 100000; i++)
{
//第一种方式
//TestModel test = ModelBuilder.Build<TestModel>(Request.Form, "txt");
//第二种方式
TestModel test = new TestModel();
try
{
test.Name = Request.Form["txtname"];
test.Count = int.Parse(Request.Form["txtcount"]);
test.IsLimit = string.Compare("true", Request.Form["txtIsLimit"], true) == 0;
test.Time = DateTime.Parse(Request.Form["txtTime"]);
}
catch { }
}

TimeSpan ts = DateTime.Now - sTime;

Response.Write(ts.TotalMilliseconds.ToString());
}


页面HTML

   <form method="post">
<input type="text" name="txtName" />
<input type="text" name="txtCount" />
<input type="text" name="txtIsLimit" />
<input type="text" name="txtTime" />
<input type="text" name="txtType" />
<input type=submit input="提交" />
</form>



3.测试结果

以10W次重复操作,取得结果如下:

利用反射消耗的时间:6781.25 MS (即:第一种方式)

手动代码消耗时间:687.5 MS (即:第二种方式)

PS:反射在性能上的损失大概是手写代码方式的9-10倍

但在均值条件下,每次反射得到实体的时间仅为:0.06781毫秒

呵呵,这种性能损失可以说是很微小的,所以,这个放心的用吧。没问题的
qinhl99 2008-12-16
  • 打赏
  • 举报
回复
mark
NqIceCoffee 2008-12-16
  • 打赏
  • 举报
回复
看15楼MSDN的解释

是值
zhbr 2008-12-16
  • 打赏
  • 举报
回复
不错,顶一下
xiaoidfw 2008-12-16
  • 打赏
  • 举报
回复
你的objValue 取得的是类型 不是值吧。
fenyuxiao 2008-12-16
  • 打赏
  • 举报
回复
学习+UP!!
NqIceCoffee 2008-12-16
  • 打赏
  • 举报
回复
public static class ModelBuilder
{
public static TModel Build<TModel>(NameValueCollection itemCollection) where TModel : new()
{
Type type = typeof(TModel);
TModel model = new TModel();
foreach (string name in itemCollection.AllKeys)
{
string value = itemCollection[name];
if (string.IsNullOrEmpty(value)) continue;

PropertyInfo property = type.GetProperty(name);
if (property != null)
{
Type t = property.PropertyType;
object objValue = null;
if (t.IsEnum)
objValue = Enum.Parse(t, value, true);
else
objValue = Convert.ChangeType(itemCollection[name], t);
property.SetValue(model, objValue, null);
}
}
return model;
}
}
NqIceCoffee 2008-12-16
  • 打赏
  • 举报
回复
发现新大陆了


Convert.ChangeType(object, type)
//一个对象,它的 Type 为 conversionType,而且它的值等效于 value。 - 或 - 如果 value 为空引用(在 Visual Basic 中为 Nothing) 且 //conversionType 不是值类型,则为空引用(在 Visual Basic 中为 Nothing)。


偶然发现这个,MSDN是好东西啊
NqIceCoffee 2008-12-16
  • 打赏
  • 举报
回复
呵呵,12的代码和我这个有一拼

貌似LINQ能动态的执行方法,而且效率很高,不知能否用这个做个尝试,一会4一下
NqIceCoffee 2008-12-16
  • 打赏
  • 举报
回复
回11楼

动态的把一个字符串转换成Type所表示的类型 (返回类型都是object)

这个如何做到用泛型?
xiaoidfw 2008-12-16
  • 打赏
  • 举报
回复
最近写的一个类,也是用的switch

switch (property[i].PropertyType.Name.Trim().ToLower())
{
case "datetime":
DateTime dateTimeValue;
if (value == null || value.ToString().Trim().Length == 0)
{
dateTimeValue = Convert.ToDateTime("1900-01-01");
}
else
{
dateTimeValue = Convert.ToDateTime(value);
}
property[i].SetValue(objReturn, dateTimeValue, null);
break;
case "int32":
Int32 intValue;
if (value == null || value.ToString().Trim().Length == 0)
{
intValue = 0;
}
else
{
intValue = Convert.ToInt32(value);
}
property[i].SetValue(objReturn, intValue, null);
break;
case "int64":
Int64 intValue64;
if (value == null || value.ToString().Trim().Length == 0)
{
intValue64 = 0;
}
else
{
intValue64 = Convert.ToInt32(value);
}
property[i].SetValue(objReturn, intValue64, null);
break;
case "decimal":
decimal decValue;
if (value == null || value.ToString().Trim().Length == 0)
{
decValue = 0;
}
else
{
decValue = Convert.ToDecimal(value);
}
property[i].SetValue(objReturn, decValue, null);
break;
case "double":
double doubleValue;
if (value == null || value.ToString().Trim().Length == 0)
{
doubleValue = 0;
}
else
{
doubleValue = Convert.ToDouble(value);
}
property[i].SetValue(objReturn, doubleValue, null);
break;
case "boolean":
bool boolValue;
if (value == null || value.ToString().Trim().Length == 0)
{
boolValue = false;
}
else
{
boolValue = Convert.ToBoolean(value);
}
property[i].SetValue(objReturn, boolValue, null);
break;
default:
//string
property[i].SetValue(objReturn, value, null);
break;
}
winner2050 2008-12-16
  • 打赏
  • 举报
回复
private static bool TryParseValue(string input, Type type, out object result)
==============================
private static bool TryParseValue<T>(string input,out T result)

用泛型,写代码的时候更少,更漂亮。
加载更多回复(10)

62,269

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧