英文:
Convert non-json string version of object to object
问题
将非 JSON 字符串转换为 DiscriminatorTags 结构类型,你可以使用自定义逻辑,解析字符串并设置结构的属性。在你的 DiscriminatorTagsBinder 类的 BindModelAsync 方法中,替换以下行:
var x = JsonSerializer.Deserialize<DiscriminatorTags>(valueProviderResult.FirstValue);
使用以下逻辑:
var stringValue = valueProviderResult.FirstValue;
if (stringValue != null)
{
    // Assuming the format is consistent, you can implement your parsing logic here
    var tagsStartIndex = stringValue.IndexOf("tags: [");
    var tagsEndIndex = stringValue.IndexOf("]", tagsStartIndex);
    if (tagsStartIndex != -1 && tagsEndIndex != -1)
    {
        var tagsSubstring = stringValue.Substring(tagsStartIndex + 7, tagsEndIndex - tagsStartIndex - 7);
        var tagsArray = tagsSubstring.Split(',').Select(tag => int.Parse(tag.Trim())).ToList();
        var discriminatorStartIndex = stringValue.IndexOf("discriminator: ");
        var discriminatorEndIndex = stringValue.IndexOf(")", discriminatorStartIndex);
        if (discriminatorStartIndex != -1 && discriminatorEndIndex != -1)
        {
            var discriminatorSubstring = stringValue.Substring(discriminatorStartIndex + 15, discriminatorEndIndex - discriminatorStartIndex - 15);
            var selected = stringValue.Contains("selected: true");
            var discriminatorTags = new DiscriminatorTags(tagsArray, discriminatorSubstring, selected);
            // Now 'discriminatorTags' holds the parsed object
        }
    }
}
这样,你就可以手动解析非 JSON 字符串并构建 DiscriminatorTags 结构对象。
英文:
How do I convert a string version of an object that is not JSON, to the object type?
I'm creating a custom model binder for this struct so that I can send it as a Query Parameter:
[Serializable]
[ModelBinder(BinderType = typeof(DiscriminatorTagsBinder))]
public struct DiscriminatorTags : IDiscriminatorTags
{
    public DiscriminatorTags(List<int> tags, string discriminator, bool selected)
    {
        this.Tags = tags;
        this.Discriminator = discriminator;
        this.Selected = selected;
    }
    [Required]
    public List<int> Tags { get; set; }
    [Required]
    public string Discriminator { get; set; }
    [Required]
    public bool Selected { get; set; }
}
The binder:
public class DiscriminatorTagsBinder : IModelBinder
{
    public DiscriminatorTagsBinder()
    {
    }
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }
        var modelName = bindingContext.ModelName;
        // Try to fetch the value of the argument by name
        var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
    
        var x = JsonSerializer.Deserialize<DiscriminatorTags>(valueProviderResult.FirstValue);
        if (valueProviderResult == ValueProviderResult.None)
        {
            return Task.CompletedTask;
        }
        bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
        var value = valueProviderResult.FirstValue;
        // Check if the argument value is null or empty
        if (string.IsNullOrEmpty(value))
        {
            return Task.CompletedTask;
        }
        bindingContext.Result = ModelBindingResult.Success(valueProviderResult);
        return Task.CompletedTask;
    }
}
The value to deserialize is actually not JSON, it is a string version of the object:
>  "DiscriminatorTags(tags: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
> 14, 15, 16, 17, 18, 900], selected: true, discriminator: GroceryItm)"
So I am getting a JsonException when I do this: var x = JsonSerializer.Deserialize<DiscriminatorTags>(valueProviderResult.FirstValue);
How do I convert the non-json string to the DiscriminatorTags struct type?
答案1
得分: 4
这可能听起来很明显,但你需要手动解析你的字符串。这里没有免费的午餐。像这样的代码可以帮助你入门:
var str = "DiscriminatorTags(tags: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 900], selected: true, discriminator: GroceryItm)";
var matches = Regex.Matches(str, @"(tags:\s*\[(.*)\])|(selected:\s(true|false))|(discriminator:\s\w*)", RegexOptions.IgnoreCase);
var tagsMatch = matches[0].ValueSpan;
var bracketStartIndex = tagsMatch.IndexOf('[');
var tagsList = tagsMatch.Slice(bracketStartIndex + 1, tagsMatch.LastIndexOf(']') - 1 - bracketStartIndex);
var list = new List<int>();
foreach (var match in Regex.EnumerateMatches(tagsList, "[0-9]+"))
{
    list.Add(Convert.ToInt32(tagsList.Slice(match.Index, match.Length).ToString()));
}
var selectedMatch = matches[1];
var isSelected = Regex.Match(selectedMatch.Value, "true|false", RegexOptions.IgnoreCase);
var discriminatorMatch = matches[2].ValueSpan;
var discriminator = discriminatorMatch[(discriminatorMatch.IndexOf(':') + 1)..].Trim();
你需要加强它来防止缺少值等情况,还要使用已编译的正则表达式实例。
英文:
This might sound obvious but you're going to have to manually parse your string. There is no free lunch here. Something like this could get you started:
var str = "DiscriminatorTags(tags: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 900], selected: true, discriminator: GroceryItm)";
var matches = Regex.Matches(str, @"(tags:\s*\[(.*)\])|(selected:\s(true|false))|(discriminator:\s\w*)", RegexOptions.IgnoreCase);
var tagsMatch = matches[0].ValueSpan;
var bracketStartIndex = tagsMatch.IndexOf('[');
var tagsList = tagsMatch.Slice(bracketStartIndex + 1, tagsMatch.LastIndexOf(']') - 1 - bracketStartIndex);
var list = new List<int>();
foreach (var match in Regex.EnumerateMatches(tagsList, "[0-9]+"))
{
    list.Add(Convert.ToInt32(tagsList.Slice(match.Index, match.Length).ToString()));
}
var selectedMatch = matches[1];
var isSelected = Regex.Match(selectedMatch.Value, "true|false", RegexOptions.IgnoreCase);
var discriminatorMatch = matches[2].ValueSpan;
var discriminator = discriminatorMatch[(discriminatorMatch.IndexOf(':') + 1)..].Trim();
You would need to harden it to guard against missing values etc. and also use a compiled instance for the Regex
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论