C#学习教程:使用LINQWhereT:someClass创建列表:publicabstractclassDataField{publicstringName{get;放;}}publicclassDataField:DataField{publicTValue{get;放;}}publicstaticListConvertXML(XMLDocumentdata){result=(fromdinXDocument.Parse(data.OuterXML).Root.Decendendants()selectnewDataField{Name=d.Name.ToString(),Value=d.Value}).Cast().ToList();返回结果;这行得通,但我希望能够修改LINQ查询的选择部分如下所示:是否可以?有什么建议么?这是一个可行的解决方案:(您必须为Type属性指定完全限定的类型名称,否则您必须以某种方式配置映射...)我使用了dynamic关键字,如果您没有C#4,则可以使用设置值的反射...publicstaticvoidTest(){stringxmlData="Value1324";列表dataFieldList=DataField.ConvertXML(xmlData);Debug.Assert(dataFieldList.Count==2);Debug.Assert(dataFieldList[0].GetType()==typeof(DataField));调试。断言(dataFieldList[1]。GetType()==typeof(DataField));}publicabstractclassDataField{publicstringName{get;放;}//////在给定XElement的情况下实例化通用DataField///publicstaticDataFieldCreateDataField(XElementelement){//确定我们处理的元素类型stringelementTypeName=element.Attribute("Type").Value;输入elementType=Type.GetType(elementTypeName);//实例化一个新的通用元素类型:DataFielddynamicdataField=Activator.CreateInstance(typeof(DataField).Ma??keGenericType(elementType));dataField.Name=element.Name.ToString();//将内部值转换为目标元素类型dynamicvalue=Convert.ChangeType(element.Value,elementType);//设置值到DataFielddataField.Value=value;返回数据字段;}//////获取根节点的所有后代并为每个///创建一个DataFieldpublicstaticListConvertXML(stringxmlData){varresult=(fromdinXDocument.Parse(xmlData).Root.DescendantNodes().OfType()选择CreateDataField(d)).ToList();返回结果;}}publicclassDataField:DataField{publicTValue{get;放;你不能在C#中轻易做到这一点泛型类型参数必须在编译时指定。您可以使用反射来做其他事情intX=1;输入listype=typeof(List);构造类型=listype.MakeGenericType(X.GetType());objectruntimeList=Activator.CreateInstance(constructed);这里我们刚刚创建了一个列表。您可以使用您的类型执行此操作,泛型类的不同实例实际上是不同的类。即DataField和DataField根本不是同一个类(!)这意味着,您不能在运行时定义泛型参数,因为它必须在编译时确定。我会说这是一个不好的做法。事实上,即使在解析了XML文件之后,您也不会知道您拥有的是什么类型的“DataField”。您也可以将它们解析为对象。然而,如果你知道你只有x个类型,你可以这样做:varDictionary>myFactoryMaps={{"Type1",(name,value)=>{returnnewDataField(name,Type1.Parse(value);}},{"Type2",(name,value)=>{returnnewDataField(name,Type2.Parse(value);}},};Termit的答案当然很棒。这里有一个小变化。publicabstractclassDataField{publicstringName{get;放;}}publicclassDataField:DataField{publicTValue{get;放;}publicTypeGenericType{get{returnthis.Value.GetType();}}}staticFuncdfSelector=newFunc(e=>{stringstrType=e.Attribute("type").Value;//如果你没有属性类型,你可以调用扩展方法来确定类型(使用正则表达式模式)//这只适用于结构类型type=Type.GetType(strType);dynamicdf=Activator.CreateInstance(typeof(DataField).Ma??keGenericType(type));df.Name=e.Attribute("name").Value;dynamicvalue=Convert.ChangeType(e.Value,type);df.Value=value;returndf;});publicstaticListConvertXML(stringxmlstring){varresult=XDocument.Parse(xmlstring).Root.Descendants("object").Select(dfSelector).ToList();返回结果;}staticvoidMain(string[]args){stringxml="HelloWorld!324";列表dfs=ConvertXML(xml);您可以通过反射创建泛型类型varinstance=Activator.CreateInstance(typeof(DataField).Ma??keGenericType(Type.GetType(typeNameFromAttribute));//这里设置属性也通过反射@Termit和@Burnzy提出了涉及工厂方法的问题是你正在为可疑返回加载一堆额外逻辑(更多测试,更多错误)的解析例程。另一种方法是使用类型方法的基于简化字符串的DataField的读取-这个问题的最佳答案。实施TypedValue方法的一部分,这很好,但只适用于值类型(不包括字符串,但有DateTimes):publicT?TypedValue()whereT:struct{try{return(T?)Convert.ChangeType(this.Value,typeof(T)));}catch{returnnull;}}我假设你想使用类型信息来执行诸如动态分配用户控件之类的操作提供字段、验证规则、正确的持久性SQL类型等。我这样做很多,它看起来有点像你的。归根结底,您应该将元数据与代码分开——@Burnzy的答案选择基于元数据代码(DataField元素的“类型”属性),这是一个非常简单的示例。如果您正在处理XML,XSD是一种非常有用且可扩展的元数据形式。至于存储每个字段的数据Content-使用字符串是因为:我发现开发这样的小框架非常有益-这是一种学习体验,你从中了解更多关于用户体验和建模的现实。我建议您首先处理四组测试用例:列表-多选外键等空值无效输入-这通常涉及保留原始值使用字符串极大地简化了所有这些,因为它允许您明确划分框架内的职责。考虑在通用模型中做包含列表的字段——它很快就会变得毛茸茸的,而且几乎在每种方法中都有一个特殊的列表很容易。有了弦乐,责任就到此为止了。最后,如果你想在不做任何事情的情况下可靠地实现这类东西,请考虑DataSets-我知道的老派-它们可以做你意想不到的各种美妙的事情,但你必须使用RTFM。这个想法的主要缺点是它与WPF数据绑定不兼容——尽管我的经验是现实与WPF数据绑定不兼容。我希望我正确地解释了你的意图-祝你好运:)不幸的是,例如C和C之间没有继承关系。但是,您可以继承常见的非泛型类,并实现泛型接口等。在这里,我使用一个显式接口实现来声明一个Object类型的Value属性,以及一个更具体类型的Value属性。值是只读的,只能通过类型化的构造函数参数进行赋值。我的结构并不完美,但它是类型安全的并且不使用反射。公共接口IValue{T值{得到;}}publicabstractclassDataField{publicDataField(stringname,objectvalue){Name=name;价值=价值;}公共字符串名称{得到;私有集;}公共对象值{得到;私有集;}}publicclassStringDataField:DataField,IValue{publicStringDataField(stringname,stringvalue):base(name,value){}stringIValue.Value{get{return(string)Value;}}}publicclassIntDataField:DataField,IValue{publicIntDataField(stringname,intvalue):base(name,value){}intIValue.Value{get{return(int)Value;}}}然后可以使用抽象基类DataField将列表声明为通用参数:varlist=newList();switch(fieldType){case"string":list.Add(newStringDataField("Item","Apple"));休息;case"int":list.Add(newIntDataField("Count",12));休息;}通过界面访问强类型文字段:publicvoidProcessDataField(DataFieldfield){varstringField=fieldasIValue;if(stringField!=null){strings=stringField.Value;}}虽然虽然其他问题主要提出了将XML元素转换为通用类实例的优雅解决方案,但我将讨论将DataField类建模为类DataField通用方法XMLelement]>的结果。在列表中选择DataField实例后,您想使用这些字段。她的多态性发挥了作用!您想要遍历您的DataFields以统一对待它们。使用泛型的解决方案通常以奇怪的switch/if狂热结束,因为没有简单的方法来根据c#中的泛型类型关联行为。您可能已经看到这样的代码(我正在尝试对所有数字DataField实例求和)varlist=newList(){newDataField(){Name="int",Value=2},newDataField(){Name=“string”,Value=“stringValue”},newDataField(){Name=“string”,Value=2f},};变量总和=0.0;foreach(vardataFieldinlist){if(dataField.GetType().IsGenericType){if(dataField.GetType().GetGenericArguments()[0]==typeof(int)){sum+=((DataField)dataField)。价值;}elseif(dataField.GetType().GetGenericArguments()[0]==typeof(float)){sum+=((DataField)dataField).Value;}//..}}这段代码一团糟!让我们尝试通用类型DataField的多态实现,并添加一些方法Sum,它接受一个旧的some并返回一个(可能修改过的)新的总和:publicclassDataField:DataField{publicTValue{get;放;}publicoverridedoubleSum(doublesum){if(typeof(T)==typeof(int)){returnsum+(int)Value;//真的不能在这里投射!}elseif(typeof(T)==typeof(float)){returnsum+(float)Value;//真的不能在这里投射!}//...返回总和;你可以想象你的迭代代码现在更清晰了,但是您仍然在代码中使用这个奇怪的switch/if语句,这就是重点:泛型并没有帮助您在错误的地方使用错误的工具。泛型是在C#中设计的,旨在为您提供编译时类型安全,以避免潜在的不安全转换操作。它们还提高了代码的可读性,但这里不是这样的:)让我们看一个多态解决方案:publicabstractclassDataField{publicstringName{get;放;}公共对象值{得到;放;}publicabstractdoubleSum(doublesum);}publicclassIntDataField:DataField{publicoverridedoubleSum(doublesum){return(int)Value+sum;}}publicclassFloatDataField:DataField{publicoverridedoubleSum(doublesum){return(float)Value+sum;我不认为你需要太多的幻想来想象你的代码的可读性/质量会增加多少。最后一点是如何创建这些类的实例。只需使用一些约定TypeName+"DataField"和Activator:Activator.CreateInstance("assemblyName",typeName);简短版本:泛型不适合您的问题,因为它不会为DataField实例的处理增加价值。使用多态方法,您可以轻松使用DataField的实例!这并非不可能,因为您可以通过反思来做到这一点。但这不是泛型设计的目的,也不是它应该如何完成的。如果你打算用反射来做泛型,你根本不能用泛型,直接用下面的类:publicclassDataField{publicstringName{get;放;}公共对象值{得到;放;您需要插入逻辑来确定来自XML的数据类型并添加您需要使用的所有类型,但这应该可以工作:以上是C#学习教程:使用LINQ创建列表,其中T:someClass共享整个东西如果对大家有用,需要了解更多C#学习教程,希望大家多多关注——result=(fromdinXDocument.Parse(data.OuterXML).Root.Descendants()letisString=true//用你的逻辑替换true来判断它是否是一个字符串.letisInt=false//用你的逻辑替换false来判断它是否是一个整数.letstringValue=isString?(DataField)newDataField{Name=d.Name.ToString(),Value=d.Value}:nullletintValue=isInt?(DataField)newDataField{Name=d.Name.ToString(),Value=Int32.Parse(d.Value)}:nullselectstringValue??intValue).ToList();,不代表立场,如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
