我有以下控制台应用程序:
using System;
using System.IO;
using System.Xml.Serialization;
using Newtonsoft.Json;
namespace OutputApp
{
public class Foo
{
public object Value1 { get; set; }
public string Value2 { get; set; }
}
public class Bar
{
public int Arg1 { get; set; }
public double Arg2 { get; set; }
}
class Program
{
public static Foo CreateFooBar()
{
return new Foo
{
Value1 = new Bar
{
Arg1 = 123,
Arg2 = 99.9
},
Value2 = "Test"
};
}
public static string SerializeXml(object obj)
{
using (var stream = new MemoryStream())
{
using (var reader = new StreamReader(stream))
{
var serializer = new XmlSerializer(obj.GetType());
serializer.Serialize(stream, obj);
stream.Position = 0;
return reader.ReadToEnd();
}
}
}
static void Main(string[] args)
{
var fooBar = CreateFooBar();
// Using Newtonsoft.Json
var json = JsonConvert.SerializeObject(fooBar, Formatting.Indented);
var xnode = JsonConvert.DeserializeXNode(json, "RootElement");
var xml = xnode.ToString();
// Using XmlSerializer, throws InvalidOperationException
var badXml = SerializeXml(fooBar);
Console.ReadLine();
}
}
}
我有两个类(class)。 Foo 类和 Bar 类。类 Foo 有一个类型为 object 的属性。这是一个要求,因为它是一个可以容纳各种对象的契约(Contract),因此我不能将属性设置为具体类型或泛型。
现在我使用 CreateFooBar() 方法组成一个虚拟的 fooBar 对象。之后,我首先将其序列化为 JSON,这与 Json.Net 配合得很好。
然后我使用 Json.Net 的 XML 转换器方法将 json 字符串转换为 XNode 对象。它也很好用。
两者的输出如下:
{
"Value1": {
"Arg1": 123,
"Arg2": 99.9
},
"Value2": "Test"
}
<RootElement>
<Value1>
<Arg1>123</Arg1>
<Arg2>99.9</Arg2>
</Value1>
<Value2>Test</Value2>
</RootElement>
虽然这行得通,但肯定不是很好,因为我必须序列化为 json 之后才将其序列化为 xml。我想直接序列化成xml。
当我使用 XmlSerializer 执行此操作时,我得到了臭名昭著的 InvalidOperationExceptoin,因为我没有使用 XmlInclude 属性装饰我的类,也没有执行 other workarounds 之一.
InvalidOperationException
The type OutputApp.Bar was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
XmlSerializer 的所有变通方法都不是一个很好的解决方案恕我直言,我不认为需要它,因为将对象序列化为 XML 没有 crappy 属性是完全可行的。
有谁知道 .NET 中可以执行此操作的优秀 Xml 序列化程序,或者是否有计划将此功能添加到 Json.Net?
有什么想法吗?
更新1
我不反对使用属性,但它需要有意义。我不喜欢 XmlInclude 属性的地方在于它迫使我陷入循环依赖。假设我有定义基类的程序集 A 和实现派生类的程序集 B。现在 XmlInclude 属性的工作方式是我必须用程序集 B 中的子类的类型名称装饰程序集 A 中的基类。这意味着我有一个循环依赖并且是不行的!
更新2
我要澄清的是,我不是在寻找一种解决方案来重构我的控制台应用程序以使其与 XmlSerializer 一起工作,我正在寻找一种方法来对我现有的内容进行 XML 序列化。
下面有一条评论提到使用 object 作为数据类型是糟糕的设计。不管这是真的还是假的,这是一个完全不同的讨论。关键是没有理由不能将其序列化为 XML,我很想找到这样的解决方案。
我个人认为创建“标记”界面是一种肮脏的设计。它滥用一个接口(interface)来解决单个 .NET 类 (XmlSerializer) 的无能为力。如果我将序列化库换成其他东西,那么整个标记界面将是多余的困惑。我不想将我的类耦合到一个序列化程序。
我正在寻找一个优雅的解决方案(如果有的话)?
最佳答案
您不需要用 XmlInclude 属性污染您的模型。您可以向 XmlSerializer's constructor 显式指示所有已知类:
var serializer = new XmlSerializer(obj.GetType(), new[] { typeof(Bar) });
同时使用 object 作为基类似乎是一种糟糕的方法。至少定义一个标记接口(interface):
public interface IMarker
{
}
您的 Bar 将实现:
public class Bar : IMarker
{
public int Arg1 { get; set; }
public double Arg2 { get; set; }
}
然后将 Foo 类的 Value1 属性特化到这个标记,而不是让它成为宇宙中最通用的类型(不可能) :
public class Foo
{
public IMarker Value1 { get; set; }
public string Value2 { get; set; }
}
因为现在it's pretty trivial在运行时获取所有正在实现标记接口(interface)的引用程序集中的所有加载类型,并将它们传递给 XmlSerializer 构造函数:
var type = typeof(IMarker);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p != type)
.Where(p => type.IsAssignableFrom(p))
.ToArray();
var serializer = new XmlSerializer(obj.GetType(), types);
现在您已经有了一个功能非常强大的 XmlSerializer,它将知道如何正确序列化实现您的标记接口(interface)的所有类型。您已经实现了与 JSON.NET 几乎相同的功能。并且不要忘记这个 XmlSerializaer 实例化应该驻留在你的 Composition Root project 中。它知道所有加载的类型。
再次使用 object 是一个糟糕的设计决策。
关于c# - 类似于 Json.Net 可以做的 XML 序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37071218/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这
我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的
我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法
我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI