0

This is a question related to inheritance of C# objects, but in the context of a protected method Newtonsoft.Json.Serialization.DefaultContractResolver

I followed the advice of this post on how to use mapping properties for serializing using Newtonsoft library. DefaultContractResolver usage

I created classes AbstractContractResolver, AbstractContractResolverFromFile, CustomClassImplementedContractResolver (custom named here for example purpose)

public abstract class AbstractContractResolver : DefaultContractResolver{
            protected Dictionary<string, string> PropertyMappings {get { return this.getPropertyMappings(); }}

            protected override string ResolvePropertyName(string propertyName)
            {
                string resolvedName = null;
                var resolved = this.getPropertyMappings().TryGetValue(propertyName, out resolvedName);
                return (resolved) ? propertyName : base.ResolvePropertyName(propertyName);
            }
}
public abstract class AbstractContractResolverFromFile : AbstractContractResolver{
            public AbstractContractResolverFromFile(string mapperFileName){
                if(string.IsNullOrEmpty(mapperFileName)){
                    throw new InvalidOperationException(string.Format("The abstract class {0} uses a mapper file as input to resolve and populate properties.  Please specify a valid mapper file!", this.GetType()));
                }
                this.MapperFileName = mapperFileName;
            }
            protected new virtual string ResolvePropertyName(string propertyName)
            {

                string field = propertyName;
                if(this.PropertyMappings.Any() && this.PropertyMappings.ContainsKey(propertyName)){
                    field = this.PropertyMappings[propertyName];
                }
                else{
                    field = base.ResolvePropertyName(propertyName);
                }
                return field;
            }

public class CustomClassImplementedContractResolver : AbstractContractResolverFromFile{

            public CustomClassImplementedContractResolver (string mapperFileName) :  base(mapperFileName){

            }

            protected override string ResolvePropertyName(string propertyName)
            {
                return base.ResolvePropertyName(propertyName);
            }

The CustomClassImplementedContractResolver inherits AbstractContractResolverFromFile which inherits from the other class and so on.

I use it like this:

string mapperfile = "filepath/to/file.json";
CustomClassImplementedContractResolver contractResolver = new CustomClassImplementedContractResolver(mapperfile);
// Custom implementation to store mappings (PropertyName, FieldSource) in a Dictionary<string, string>
await contractResolver.PopulatePropertyMappings();
                
// Reading JSON and deserializing
using(TextReader tr = new StreamReader(jsonfile)){
    string jsoncontent = await tr.ReadToEndAsync();
    try{
        var settings = new JsonSerializerSettings();
        // Set the ContractResolver
        settings.ContractResolver = contractResolver;
        var item = JsonConvert.DeserializeObject<CustomClass>(jsoncontent, settings);

Issue -

Please have a look at my implementations of the protected function ResolvePropertyName in all these classes above and help me find the issue.

I think I am incorrectly overriding - and newing the method to override further...

My custom mappings created (from file) cannot be fetched because the incorrect ResolvePropertyName is called...

  • When DeserializeObject executes, the code calls the ResolvePropertyName internally, but the current contractResolver does not call the overridden method, it actually calls the first base AbstractContractResolver.ResolvePropertyName. In other words it I put breakpoints in all 4 functions (including CustomClassImplementedContractResolver.ResolvePropertyName), but it only executes the AbstractContractResolver function.

  • Strangely: I use Visual Studio Code and pressing F12 on base.ResolvePropertyName navigates correctly (as I expect my implementation to be) from each inherited function until base.

CvRChameleon
  • 367
  • 1
  • 5
  • 29

1 Answers1

1

In AbstractContractResolverFromFile change

protected new virtual string ResolvePropertyName

to

protected override string ResolvePropertyName

New-ing something hides the inherited implementation and I would generally recommend avoiding it. It is something to be aware of though as you might come across it in code.

Ben
  • 757
  • 4
  • 14
  • Sorry Ben, but I do not think I am able to `override` and `virtual` a function at the same time. `AbstractContractResolver` inherits from the Newtonsoft's `DefaultContractResolver`. – CvRChameleon Nov 16 '20 at 12:06
  • Yes sorry it should just be `protected override string ResolvePropertyName` I will update my answer – Ben Nov 16 '20 at 14:06
  • This solution is still using `virtual override` which is not a possible thing, unless its with more recent up to date C# versions (and Visual Studio) compilers. Dotnet Core 5 (newest since last week) with C# on VS Code at least does not allow overriding and virtualizing at the same time. – CvRChameleon Nov 16 '20 at 14:33
  • Sorry I really messed up my answer, that should be it now, just change new virtual to override. – Ben Nov 16 '20 at 14:35
  • Thanks @Ben, I tried that before even posting this question. I have decided to abandon the overrides of the `DefaultContractResolver`, and just created an Extension method that does what I want to do depending on the inheriting type (`FromFile` or `AbstractContractResolver` resolvers). Works already - `newing` / `virtualizing` behaves strangely (at least in terms of two levels of inheritance that I tried). – CvRChameleon Nov 16 '20 at 14:38