类型上的避难化构造函数中的每个参数必须绑定到避难所化的对象属性或字段
我有以下简单的课程:
public abstract class GitObject
{
public Repository Repository { get; set; }
public abstract string Serialize();
public abstract void Deserialize(string data);
public class Blob : GitObject
{
public string Data { get; set; }
public Blob(Repository repository, string data = null)
{
if (data != null) Data = File.ReadAllText(data);
Repository = repository;
}
public override string Serialize()
{
return JsonSerializer.Serialize(this);
}
public override void Deserialize(string data)
{
Blob blobData = JsonSerializer.Deserialize<Blob>(data);
}
}
}
我知道可能有很多改进的空间(我很高兴听到它)。但是,方法delelialize
给出了
Each parameter in the deserialization constructor on type 'CustomGit.Repository'
must bind to an object property or field on deserialization. Each parameter name must
match with a property or field on the object. The match can be case-insensitive.
测试错误的错误,如果此方法按预期工作,我使用此方法(这也会引发错误)
FileInfo file = new FileInfo(Path.Combine(repository.GitDirectory.FullName, "code.txt"));
GitObject.Blob firstBlob = new GitObject.Blob(repository, file.FullName);
var json = firstBlob.Serialize();
GitObject.Blob secondBlob = new GitObject.Blob(repository);
secondBlob.Deserialize(json);
我在做什么错,一般应该改变什么?
I have the following simple classes :
public abstract class GitObject
{
public Repository Repository { get; set; }
public abstract string Serialize();
public abstract void Deserialize(string data);
public class Blob : GitObject
{
public string Data { get; set; }
public Blob(Repository repository, string data = null)
{
if (data != null) Data = File.ReadAllText(data);
Repository = repository;
}
public override string Serialize()
{
return JsonSerializer.Serialize(this);
}
public override void Deserialize(string data)
{
Blob blobData = JsonSerializer.Deserialize<Blob>(data);
}
}
}
I know there is probably a LOT of room for improvement ( and I a am happy to hear about it ). However, the method Deserialize
gives me the error
Each parameter in the deserialization constructor on type 'CustomGit.Repository'
must bind to an object property or field on deserialization. Each parameter name must
match with a property or field on the object. The match can be case-insensitive.
For testing if this method works as intended I use this approach (which also throws the error)
FileInfo file = new FileInfo(Path.Combine(repository.GitDirectory.FullName, "code.txt"));
GitObject.Blob firstBlob = new GitObject.Blob(repository, file.FullName);
var json = firstBlob.Serialize();
GitObject.Blob secondBlob = new GitObject.Blob(repository);
secondBlob.Deserialize(json);
What am I doing wrong and what should I change in general?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您正在遇到与参数化构造函数有关的两个单独的问题。如文档页面中所述, 使用system.text.json 使用不可变的类型和非公共配件:
您的第一个问题是类型<代码>存储库。您不会在问题中显示它,但我认为它看起来像这样:
如果是这样,您的问题是构造函数参数的名称与
gitdirectory
相对应属性名称或参数类型不是相同的。演示小提琴#1 在这里。
要解决此问题,您必须:
添加一个公共参数无参数构造函数,然后制作
repository
是可变的(即添加gitdirectory
)或>
添加具有相同类型和名称的参数的构造函数,属性
gitdirectory
,并用[jsonconstructor]
。标记
采用选项#2,您的
存储库
类型现在应该看起来像:现在
Respository
将成功地进行序列化。演示小提琴#2 在这里。但是,您现在将遇到第二个问题,即
blob
类型也不会往返。在这种情况下,blob
确实具有一个唯一的参数化构造函数,data
,完全不同:属性
数据
对应于文件的文本内容,而参数data
则对应于文件。因此,当挑选blob
时,您的代码将尝试读取名称等于文件内容并失败的文件。在我看来,这种不一致是编程风格差,并且可能会使其他开发人员以及System.Text.json感到困惑。而是考虑添加出厂方法以从文件或文件内容中创建
blob
,然后删除相应的构造函数参数。因此,您的blob
应该看起来像:您将构造和往返如下:
最终工作演示小提琴在这里。
[1] 该文档于2023年更新。当时提出了该问题,文档
You are encountering two separate problems related to deserializing types with parameterized constructors. As explained in the documentation page How to use immutable types and non-public accessors with System.Text.Json:
Your first problem is with the type
Repository
. You don't show it in your question, but I assume it looks something like this:If so, your problem here is that either the name of the constructor argument corresponding to
GitDirectory
is not the same as the property name or the type of the argument is not the same.Demo fiddle #1 here.
To fix this, you must either:
Add a public parameterless constructor and make
Repository
be mutable (i.e. add a setter forGitDirectory
), orAdd a constructor with an argument of the same type and name as the property
GitDirectory
, and mark it with[JsonConstructor]
.Adopting option #2, your
Repository
type should now look like:And now
Respository
will deserialize successfully. Demo fiddle #2 here.However, you will now encounter your second problem, namely that the
Blob
type will not round-trip either. In this case,Blob
does have a unique parameterized constructor whose argument names and types correspond precisely to properties -- but the semantics of one of them,data
, are completely different:The property
Data
corresponds to the textual contents of a file, while the argumentdata
corresponds to the file name of a file. Thus when deserializingBlob
your code will attempt to read a file whose name equals the file's contents, and fail.This inconsistency is, in my opinion, poor programming style, and likely to confuse other developers as well as System.Text.Json. Instead, consider adding factory methods to create a
Blob
from a file, or from file contents, and remove the corresponding constructor argument. Thus yourBlob
should look like:And you would construct and round-trip it as follows:
Final working demo fiddle here.
[1] The documentation was updated in 2023. At the time this question was asked, the documentation merely stated
就我而言,我是从抽象类继承的。这堂课有一个空的构造函数,我的孩子课也是。我什至尝试了我传递给控制器的数据对象类的自定义jsonConverter,该controlter使用[Body]注释作为参数接收它。
那没有帮助。我的问题是我的抽象课没有{get;放; }关于其公共属性。我使用参数化的构造函数创建了此类,以避免它是贫血的域模型,但不认为它需要getters和setters。确保JSON属性名称(如果有属性)也匹配。我花了几个小时!
In my case I was inheriting from an abstract class. This class had an empty constructor and so did my child class. I even tried a custom JsonConverter for my data object class I was passing to my controller, which was receiving it using the [FromBody] annotation as a parameter.
That did not help.. my problem was my abstract class did not have { get; set; } on its public properties. I created this class with a parameterized constructor to avoid it being an anemic domain model, but did not think it would need the getters and setters. Be sure the JSON Property names (if you have attributes) also match. I spent hours on this one!