title: C# Using Newtonsoft.json DefaultContractResolver IValueProvider to replace Data crashes
body: <p>I am attempting to use Newtonsoft.json DefaultContractResolver to output json. When the ContractResolver finds a class of type IVariant, it sets the output based upon the IVariant's &quot;TypeName&quot;</p>
  <p>Without my ContractResolver code the json would look something like this:</p>
  <pre class="lang-none prettyprint-override"><code>{
    &quot;Data&quot; :
    {
      &quot;Aim&quot; :
        {
          &quot;Joystick&quot; :
          {
            &quot;Test&quot; : &quot;Test&quot;
          }, 
          &quot;Button&quot; :
          {
            &quot;Test&quot; : &quot;Test2&quot;
          }
        }
    }
  }
  </code></pre>
  <p>and with my resolver, It replaces &quot;Aim&quot; with either Joystick, or Button, and look like this:</p>
  <pre class="lang-none prettyprint-override"><code>{
    &quot;Data&quot; :
    {
      &quot;Button&quot; :
      {
        &quot;Test&quot; : &quot;Test2&quot;
      }
    }
  }
  </code></pre>
  <p>Below is the full code I used.</p>
  <pre><code>  public class JsonTester
    {
      public void Test()
      {
        var d = new Outer();
  
        var json = JsonConvert.SerializeObject(d, new JsonSerializerSettings()
        {
          ContractResolver = new JsonContractResolver()
        });
      }
    }
  
    public interface IVariant
    {
      object Data { get; }
  
      string TypeName { get; set; }
    }
  
    public interface IVariantData
    {
    }
  
    [DataContract]
    public class Variant&lt;TEnum, TData&gt; : IVariant where TEnum : struct where TData : class, IVariantData, new()
    {
      [DataMember]
      public TData Data { get; }
  
      public string TypeName { get; set; }
  
      object IVariant.Data =&gt; Data;
  
      public Variant()
      {
        Data = new TData();
      }
    }
  
    [DataContract]
    public sealed class VariantHolder
    {
      [DataContract]
      public class Joystick
      {
        [DataMember]
        public string Test { get; set; } = &quot;Test&quot;;
      }
  
      [DataContract]
      public class Button
    {
      [DataMember]
      public string Test2 { get; set; } = &quot;Test2&quot;;
    }
  
      [DataContract]
      public sealed class AimΞVariant : Variant&lt;AimΞVariant.VariantEnum, AimΞVariant.VariantData&gt;
    {
      public AimΞVariant()
      {
        TypeName = &quot;Button&quot;;
      }
      public enum VariantEnum : byte
      {
        Joystick,
        Button
      }
  
      [DataContract]
      public sealed class VariantData : IVariantData
      {
        [DataMember]
        Joystick _Joystick = new Joystick();
  
        [DataMember]
        Button _Button = new Button();
  
        public Button Button =&gt; _Button;
        public Joystick Joystick =&gt; _Joystick;
      }
    }
  
      [DataMember]
      AimΞVariant Aim = new AimΞVariant();
    }
  
    [DataContract]
    public sealed class Outer
    {
      [DataMember]
      VariantHolder Data = new VariantHolder();
    }
  
    public class JsonContractResolver : DefaultContractResolver
    {
      public JsonContractResolver()
      {
  
      }
  
      protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
      {
        return base.CreateProperty(member, memberSerialization);
      }
  
      protected override IList&lt;JsonProperty&gt; CreateProperties(Type type, MemberSerialization memberSerialization)
    {
      var list = type.GetProperties().Where(x =&gt; x.GetCustomAttributes().Any(a =&gt; a.GetType() == typeof(DataMemberAttribute))).Select(p =&gt;
      {
        var member = p.GetCustomAttribute&lt;DataMemberAttribute&gt;();
  
        return new JsonProperty()
        {
          PropertyName = p.Name,
          PropertyType = p.PropertyType,
          Readable = true,
          Writable = true,
          ValueProvider = CreateMemberValueProvider(p),
          DefaultValueHandling = DefaultValueHandling.Include
        };
      }).Concat(
      type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Where(x =&gt; x.GetCustomAttributes().Any(a =&gt; a.GetType() == typeof(DataMemberAttribute))).Select(p =&gt;
      {
        var member = p.GetCustomAttribute&lt;DataMemberAttribute&gt;();
        return new JsonProperty()
        {
          PropertyName = p.Name,
          PropertyType = p.FieldType,
          Readable = true,
          Writable = true,
          ValueProvider = CreateMemberValueProvider(p),
          DefaultValueHandling = DefaultValueHandling.Include
        };
      })).ToList();
  
      return list;
    }
  
      protected override IValueProvider CreateMemberValueProvider(MemberInfo member)
      {
        Type type = member.MemberType == MemberTypes.Property ? ((PropertyInfo)member).PropertyType : ((FieldInfo)member).FieldType;
  
        if (typeof(IVariant).IsAssignableFrom(type))
        {
          return new IVariantValueProvider(member, type);
        }
  
        return base.CreateMemberValueProvider(member);
      }
    }
  
    internal class IVariantValueProvider : IValueProvider
    {
      private MemberInfo member;
      private Type type;
  
      public IVariantValueProvider(MemberInfo member, Type type)
      {
        this.member = member;
        this.type = type;
      }
  
      public object GetValue(object target)
      {
        IVariant variant;
        
        switch (member)
        {
        case PropertyInfo p:
          variant = (IVariant)p.GetValue(target);
          break;
        case FieldInfo f:
          variant = (IVariant)f.GetValue(target);
          break;
        default:
          throw new InvalidCastException();
        }
  
        var dataType = variant.TypeName;
  
        var property = variant.Data.GetType().GetProperty(dataType);
  
        var value = property.GetValue(variant.Data);
  
        return value;
      }
  
      public void SetValue(object target, object value)
      {
        throw new NotImplementedException();
      }
    }
  </code></pre>
  <p>The code crashes somewhere inside JsonConvert.SeralizeObject.</p>
  <blockquote>
  <pre class="lang-none prettyprint-override"><code>Newtonsoft.Json.JsonSerializationException: 'Error getting value from 'Data' on 'Iugo.Test.VariantHolder+Button'.'
  
  Inner Exception: InvalidCastException: Unable to cast object of type 'Button' to type 'Iugo.Test.Variant`2[Iugo.Test.VariantHolder+AimΞVariant+VariantEnum,Iugo.Test.VariantHolder+AimΞVariant+VariantData]'.
  </code></pre>
  </blockquote>