How to pass arguments to a non-default constructor?(如何将参数传递给非默认构造函数?)
问题描述
我大概有以下图片:
public class Foo
{
public Foo(Bar bar, String x, String y)
{
this.Bar = bar;
this.X = x;
this.Y = y;
}
[JsonIgnore]
public Bar Bar { get; private set; }
public String X { get; private set; }
public String Y { get; private set; }
}
public class Bar
{
public Bar(String z)
{
this.Z = z;
}
public String Z { get; private set; }
}
我想在反序列化期间以某种方式将 Bar 类型的对象传递给 Foo 类型的构造函数,即:
I want somehow to pass an object of type Bar to a constructor of type Foo during deserialization, i.e:
var bar = new Bar("Hello world");
var x = JsonConvert.DeserializeObject<Foo>(fooJsonString, bar);
推荐答案
以下是我对解决问题的想法:
Here are my thoughts regarding problem solution:
Json.Net 的自定义反序列化 api 不透明,即影响我的类层次结构.
Json.Net's custom deserialization api is not transparent, i.e. affects my class hierarchy.
实际上,如果您的项目中有 10-20 个类,这不是问题,但如果您有包含数千个类的大型项目,您对需要使用 Json 遵守 OOP 设计这一事实并不特别高兴.净需求.
Actually it's not a problem in case when you have 10-20 classes in your project, though if you have huge project with thousands of classes, you are not particularly happy about the fact that you need comply your OOP design with Json.Net requirements.
Json.Net 非常适合在创建后填充(初始化)的 POCO 对象.但这并非在所有情况下都是正确的,有时您会在构造函数中初始化对象.为了使初始化发生,您需要传递正确"的参数.这些正确"的参数可以在序列化文本中,也可以在一段时间之前已经创建和初始化.不幸的是,Json.Net 在反序列化期间将默认值传递给他不理解的参数,在我的情况下,它总是导致 ArgumentNullException.
Json.Net is good with POCO objects which are populated (initialized) after they are created. But it's not truth in all cases, sometimes you get your objects initialized inside constructor. And to make that initialization happen you need to pass 'correct' arguments. These 'correct' arguments can either be inside serialized text or they can be already created and initialized some time before. Unfortunately Json.Net during deserialization passes default values to arguments that he doesn't understand, and in my case it always causes ArgumentNullException.
这是一种允许在反序列化期间使用任何序列化或非序列化参数集创建真正的自定义对象的方法,主要问题是该方法不是最佳的,它需要每个需要自定义反序列化的对象的 2 个反序列化阶段,但它可以工作并允许以您需要的方式反序列化对象,所以这里是:
Here is approach that allows real custom object creation during deserialization using any set of arguments either serialized or non-serialized, the main problem is that the approach sub-optimal, it requires 2 phases of deserialization per object that requires custom deserialization, but it works and allows deserializing objects the way you need it, so here goes:
首先我们按照以下方式重新组装 CustomCreationConverter 类:
First we reassemble the CustomCreationConverter class the following way:
public class FactoryConverter<T> : Newtonsoft.Json.JsonConverter
{
/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotSupportedException("CustomCreationConverter should only be used while deserializing.");
}
/// <summary>
/// Reads the JSON representation of the object.
/// </summary>
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <param name="existingValue">The existing value of object being read.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>The object value.</returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
T value = CreateAndPopulate(objectType, serializer.Deserialize<Dictionary<String, String>>(reader));
if (value == null)
throw new JsonSerializationException("No object created.");
return value;
}
/// <summary>
/// Creates an object which will then be populated by the serializer.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns></returns>
public abstract T CreateAndPopulate(Type objectType, Dictionary<String, String> jsonFields);
/// <summary>
/// Determines whether this instance can convert the specified object type.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns>
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
/// </returns>
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
/// <summary>
/// Gets a value indicating whether this <see cref="JsonConverter"/> can write JSON.
/// </summary>
/// <value>
/// <c>true</c> if this <see cref="JsonConverter"/> can write JSON; otherwise, <c>false</c>.
/// </value>
public override bool CanWrite
{
get
{
return false;
}
}
}
接下来我们创建将创建我们的 Foo 的工厂类:
Next we create the factory class that will create our Foo:
public class FooFactory : FactoryConverter<Foo>
{
public FooFactory(Bar bar)
{
this.Bar = bar;
}
public Bar Bar { get; private set; }
public override Foo Create(Type objectType, Dictionary<string, string> arguments)
{
return new Foo(Bar, arguments["X"], arguments["Y"]);
}
}
这里是示例代码:
var bar = new Bar("BarObject");
var fooSrc = new Foo
(
bar,
"A", "B"
);
var str = JsonConvert.SerializeObject(fooSrc);
var foo = JsonConvert.DeserializeObject<Foo>(str, new FooFactory(bar));
Console.WriteLine(str);
在这种情况下 foo 包含一个我们需要在反序列化期间传递给 Foo 构造函数的参数.
In this case foo contains an argument that we needed to pass to a Foo constructor during deserialization.
这篇关于如何将参数传递给非默认构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何将参数传递给非默认构造函数?
- CanBeNull和ReSharper-将其用于异步任务? 2022-01-01
- Azure Active Directory 与 MVC,客户端和资源标识同一 2022-01-01
- 带问号的 nvarchar 列结果 2022-01-01
- C# 通过连接字符串检索正确的 DbConnection 对象 2022-01-01
- 使用 rss + c# 2022-01-01
- 在 C# 中异步处理项目队列 2022-01-01
- Windows 喜欢在 LINUX 中使用 MONO 进行服务开发? 2022-01-01
- 为什么 C# 中的堆栈大小正好是 1 MB? 2022-01-01
- 是否可以在 .Net 3.5 中进行通用控件? 2022-01-01
- 在 LINQ to SQL 中使用 contains() 2022-01-01