I'm getting data in json format from different sources and I'm trying to map them to objects implementing the same interface.
The json variable looks something like this from feed 1:
{"identifier": 232, "type": "Feed1"}
And I'm serializing it using this object:
[DataContract]
public class Class A : InterfaceA
{
[DataMember(Name = "identifier")]
public int Id{ get; set; }
[DataMember(Name = "type")]
public FeedType Type { get; set; }
}
[DataContract]
public enum FeedType
{
[EnumMember(Value = "Feed1")]
FeedA,
[EnumMember(Value = "Feed2")]
FeedB,
[EnumMember(Value = "Feed3")]
FeedC
}
The interface looks like this:
public interface InterfaceA
{
int Id {get;set;}
FeedType Type{get;set;}
}
In feed 2, the object looks like this:
{"identifier": 232, "feedType": "A"}
How can I create another object that implements the same interface and will return the same enum? How do I set up the DataContract?
EDIT:
I serialize it like this
var serializer = new DataContractJsonSerializer(ClassA);
var ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
var serializedObject = serializer.ReadObject(ms);
I'll give an answer using Json.Net (of course if you are open to use a different serializer)
string json = #"{""identifier"": 232, ""type"": ""Feed2""}";
var classa = JsonConvert.DeserializeObject<ClassA>(json);
.
public interface InterfaceA
{
int Id { get; set; }
FeedType Type { get; set; }
}
public class ClassA : InterfaceA
{
[JsonProperty("identifier")]
public int Id{ get; set; }
[JsonConverter(typeof(MyConverter))] //<--- !!!
[JsonProperty("type")]
public FeedType Type { get; set; }
}
[DataContract]
public enum FeedType
{
[EnumMember(Value = "Feed1")]
FeedA,
[EnumMember(Value = "Feed2")]
FeedB,
[EnumMember(Value = "Feed3")]
FeedC
}
And this is the type converter class
public class MyConverter : Newtonsoft.Json.Converters.StringEnumConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(FeedType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var field = objectType.GetFields()
.First(f => f.GetCustomAttributes(false)
.Any(a=>a.GetType()==typeof(EnumMemberAttribute) &&
((EnumMemberAttribute)a).Value.Equals(reader.Value)));
return field.GetValue(null);
}
}
so if you want a class B
[DataContract]
public class ClassB : InterfaceA
{
[DataMember(Name = "identifier")]
public int Id{ get; set; }
[DataMember(Name = "type")]
public FeedType Type { get; set; }
}
var serializer = new DataContractJsonSerializer(ClassB);
var ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
var serializedObject = serializer.ReadObject(ms);
Thats it?! you could use a generic if you wanted to reuse the code:
public T SerialiseObject<T>(string json) where T : InterfaceA
{
var serializer = new DataContractJsonSerializer(T);
var ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
return (T)serializer.ReadObject(ms);
}
then call it:
SerialiseObject<ClassA>(json);
SerialiseObject<ClassB>(json);
to explain more fully you could not have
public class ClassA : InterfaceA
{
public ns1.FeedType Type{get; set;}
}
and
public class ClassB : InterfaceA
{
public ns2.FeedType Type{get; set;}
}
this would not compile as InterfaceA would expect either ns1.FeedType or ns2.FeedType
Related
I have some JSON that looks like this:
{
"fs_Unique_Form_Name": {
"title": "Title Text",
"description": "This is the description.",
"code": "123"
},
"stackId": 1,
"stateId": 1,
"timeStamp": "2020-11-04:10.30.48"
}
I am using Newtonsoft.Json to try and deserialize it to a model object, but am having a hard time with the dynamic keys; I'd like to make that property generic if possible since the inner object is always the same.
Here are the models I am trying to use:
public class FormDetail {
[JsonProperty(PropertyName = "title")]
public string Title { get; set; }
[JsonProperty(PropertyName = "description")]
public string Description { get; set; }
[JsonProperty(PropertyName = "code")]
public string Code { get; set; }
}
public class FormResponse {
[JsonProperty(PropertyName = "NEED TO FIGURE THIS OUT")]
public FormDetail FormDetail { get; set; }
[JsonProperty(PropertyName = "stackId")]
public int StackId { get; set; }
[JsonProperty(PropertyName = "stateId")]
public int StateId { get; set; }
[JsonProperty(PropertyName = "timeStamp")]
public string TimeStamp { get; set; }
}
I would like to get the whole JSON deserialized into the FormResponse object, but am having difficulty because the fs_Unique_Form_Name key is dynamic after the fs_ portion, but the keys (title, description, code) in that object are static.
Is there a way for me to do something where I can deserialize it to the FormDetail property when the JSON key starts with fs_?
You can do this by making a custom JsonConverter for your FormResponse class. Below is the code you would need for the converter:
public class FormResponseConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(FormResponse);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Load the JSON into a JObject so we can inspect it.
JObject obj = JObject.Load(reader);
// Populate all the known properties on a new instance of FormResponse.
FormResponse response = new FormResponse();
serializer.Populate(obj.CreateReader(), response);
// Now find the first property in the JObject whose name starts with "fs_".
// If there is one, use it to populate the FormDetail on the response.
JProperty prop = obj.Properties().FirstOrDefault(p => p.Name.StartsWith("fs_"));
response.FormDetail = prop != null ? prop.Value.ToObject<FormDetail>(serializer) : null;
return response;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
To use the converter, add a [JsonConverter] attribute to your FormResponse class as shown below. You can remove the [JsonProperty] attribute from the FormDetail property as it is not needed.
[JsonConverter(typeof(FormResponseConverter))]
public class FormResponse
{
public FormDetail FormDetail { get; set; }
[JsonProperty(PropertyName = "stackId")]
public int StackId { get; set; }
[JsonProperty(PropertyName = "stateId")]
public int StateId { get; set; }
[JsonProperty(PropertyName = "timeStamp")]
public string TimeStamp { get; set; }
}
Then you can deserialize as you normally would:
var response = JsonConvert.DeserializeObject<FormResponse>(json);
Here is a working demo: https://dotnetfiddle.net/jHyRcK
There are many ways to do it.
For example, let's create a custom reader.
class CustomJsonReader : JsonTextReader
{
public CustomJsonReader(TextReader reader) : base(reader) { }
public override object Value
{
get
{
if (base.TokenType == JsonToken.PropertyName &&
base.Value.ToString().StartsWith("fs_"))
return "FormDetail";
return base.Value;
}
}
}
Use it like this
FormResponse response;
var serializer = JsonSerializer.CreateDefault();
using (var streamReader = new StreamReader("test.json"))
using (var jsonReader = new CustomJsonReader(streamReader))
{
response = serializer.Deserialize<FormResponse>(jsonReader);
}
In this case, the FormDetail property does not need the JsonProperty attribute.
I got a JSON response like:
{
"items": [
{
"document": {
"id": "123",
"title": "title2",
"description": "Description1",
"type": "Typ1"
}
},
{
"document": {
"id": "456",
"title": "title2",
"description": "desctiption2",
"type": "Type2",
"Type2Property": "Type2Property"
}
}
]
}
As you can see above I have two values (just for example) with different properties.
In my code, I have two classes.
public class Type1
{
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Type { get; set; }
}
public class Type2
{
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Type { get; set; }
public string Type2Property {get; set;}
}
Question: How can I create one generic list which combines Type1 and Type2. In the future, I can have more TypeX (with different properties). So, I'd like to parse JSON into a generic list.
Update: I can filter json by the Type property from the JSON.
One way to solve this problem is to create a custom JsonConverter and override its ReadJson method.
I've introduced a couple of helper classes to be able to parse the whole sample json:
public class TopLevel
{
public MidLevel[] Items { get; set; }
}
public class MidLevel
{
public IDocument Document { get; set; }
}
[JsonConverter(typeof(DocumentTypeConverter))]
public interface IDocument
{
}
I've created an IDocument marker interface. If you wish you can use abstract class.
I've decorated the interface with a JsonConverterAttribute and specified there the custom converter.
I've changed the Type1 and Type2 classes to implement this interface:
public class Type1 : IDocument
{
...
public string Type { get; set; }
}
public class Type2 : IDocument
{
...
public string Type { get; set; }
public string Type2Property { get; set; }
}
The DocumentTypeConverter naive implementation would look like this:
(Obviously you can make more type-safe)
public class DocumentTypeConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
=> throw new NotImplementedException();
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
var jObject = JObject.Load(reader);
switch (jObject["type"].Value<string>())
{
case "Typ1":
{
var obj = new Type1();
serializer.Populate(jObject.CreateReader(), obj);
return obj;
}
case "Type2":
{
var obj = new Type2();
serializer.Populate(jObject.CreateReader(), obj);
return obj;
}
default:
throw new Exception();
}
}
public override bool CanConvert(Type objectType)
=> objectType == typeof(IDocument);
}
The CanConvert tells us that this convert can be used against IDocuments.
The ReadJson branches its logic based on the "type" field.
The actual conversion done with the Populate instead of JsonCovert.Deserialize to avoid infinite recursion.
Finally, the usage is that simple:
static void Main(string[] args)
{
var sampleJson = File.ReadAllText("sample.json");
var sample = JsonConvert.DeserializeObject<TopLevel>(sampleJson);
Console.ReadLine();
}
I'm new in C# and I want to get a JSON from my app in heroku. Before I did it in javascript with no problems but I'm triying to do it in C# now.
My code is:
namespace FirstApp
{
public class AOA
{
public Data data { get; set; }
public static void Main()
{
var json = string.Empty;
var aoa = new List<AOA>();
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(#"http://beautyglam.herokuapp.com/aoa/eyeliner?page=1");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
json = reader.ReadToEnd();
aoa = JsonConvert.DeserializeObject<List<AOA>>(json);
Console.WriteLine("DATOS");
Console.WriteLine(json);
Console.WriteLine(aoa[0].data);
}
catch(Exception e)
{
Console.WriteLine("Errorrr: " + e);
}
}
}
public class Data
{
public string category { get; set; }
public int pages { get; set; }
public string name { get; set; }
public int? price { get; set; }
public string id { get; set; }
public string img { get; set; }
}
}
The returned json is something like:
[{"category":"AOA Eye Liner","pages":0},{"name":"AOA Starlet Eyeliner- Spotlight","price":150,"id":"751612657678","img":"//cdn.shopify.com/s/files/1/0882/6874/products/AOA-164-MAIN_large.jpg?v=1539192189"},{"name":"AOA Starlet Eyeliner- Hollywood","price":150,"id":"751612592142","img":"//cdn.shopify.com/s/files/1/0882/6874/products/AOA-166-MAIN_large.jpg?v=1539192156"},{"name":"AOA Starlet Eyeliner- Fame","price":150,"id":"751612559374","img":"//cdn.shopify.com/s/files/1/0882/6874/products/AOA-169-MAIN_large.jpg?v=1539192087"},{"name":"AOA Starlet Eyeliner- Superstar","price":150,"id":"751612526606","img":"//cdn.shopify.com/s/files/1/0882/6874/products/AOA-167-MAIN_large.jpg?v=1539192203"},{"name":"AOA Starlet Eyeliner- Paparazzi","price":150,"id":"751612461070","img":"//cdn.shopify.com/s/files/1/0882/6874/products/AOA-165-MAIN_large.jpg?v=1539192338"},{"name":"AOA Starlet Eyeliner- Golden Girl","price":150,"id":"751612329998","img":"//cdn.shopify.com/s/files/1/0882/6874/products/AOA-168-MAIN_large.jpg?v=1539192127"},{"name":"AOA Wonder Liquid Liner - Black","price":150,"id":"194917793806","img":"//cdn.shopify.com/s/files/1/0882/6874/products/AOA-036-1_large.jpg?v=1522944978"},{"name":"AOA Wonder Liquid Liner - Dark Brown","price":150,"id":"194917335054","img":"//cdn.shopify.com/s/files/1/0882/6874/products/AOA-037-1_large.jpg?v=1522944879"}]
I want to use it like in Javascript, for example:
aoa[0].name;
Your class representation of your json structure is not valid for your example. Also, your json structure needs to be parsed with some special deserializer because it is not contains consist values.
You have an array of json object but they are not have same type.
You need 3 classes which one represents category and pages, one represents name,price,id,img and one for the root which containts those two classes.
Here is what it should look like:
class RootObj {
public Category category { get; set; }
public List<Detail> details { get; set; }
}
class Category {
public string category { get; set; }
public int pages { get; set; }
}
class Detail {
public string name { get; set; }
public int price { get; set; }
public string id { get; set; }
public string img { get; set; }
}
Here is custom deserializer:
class CustomObjectConverter<T> : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JArray array = JArray.Load(reader);
RootObj result = new RootObj();
result.category = array[0].ToObject<Category>();
array.RemoveAt(0);
result.details = array.ToObject<List<Detail>>();
return result;
}
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(RootObj));
}
}
Main :
string jsonText = File.ReadAllText("json.txt");
var deserializer = new JsonSerializerSettings();
deserializer.Converters.Add(new CustomObjectConverter<RootObj>());
var result = JsonConvert.DeserializeObject<RootObj>(jsonText, deserializer);
Now you can access the properties as :
Console.WriteLine(result.category.category);
Output is :
AOA Eye Liner
You can customize it according to your use cases.
I have these interfaces:
public interface IParameter
{
string Name { get; }
object UntypedValue { get; set; }
}
public interface IValidationPolicy<T>
{
bool Validate(T toValidate);
T Default();
}
A parameter base class
[Serializable]
public abstract class ParameterBase : IParameter
{
public abstract string Name { get; protected set; }
public abstract object UntypedValue { get; set; }
}
A parameter concrete class (I have more but them are quite similar):
public class Parameter<T, V> : ParameterBase where V : IValidationPolicy<T>
{
[XmlAttribute("Name")]
public override string Name { get; protected set; }
[XmlIgnore]
protected V validation_policy_;
[XmlElement("AnyValidation", Type = typeof(AnyValidation<>))]
[XmlElement("MultiOptionsValidation", Type = typeof(MultiOptionsValidation<>))]
[XmlElement("RangeValidation", Type = typeof(RangeValidation<>))]
[XmlElement("TextValidation", Type = typeof(TextValidation))]
public V Validation
{
get
{
return validation_policy_;
}
}
[XmlIgnore]
protected T value_;
[XmlElement("Value")]
public T Value
{
get
{
return value_;
}
set
{
if (validation_policy_.Validate(value))
{
value_ = value;
}
}
}
[XmlIgnore]
public object UntypedValue
{
get
{
return Value;
}
set
{
throw new NotImplementedException();
}
}
}
And an XMLParameter class:
public class XMLParameter : INotifyPropertyChanged
{
public string Description { get; set; }
public int PasswordLevel { get; set; }
public bool Enabled { get; set; }
public ParameterBase Parameter { get; set; }
}
How can I serialize and deserialize a list of XMLParameters?
In particular I have problem on serializing the IParameter objects.
Since the interface is not serializable as first attempt I created a base abstract class ParameterBase and derive the Parameter from it.
But when I try to serialize it in a test method:
var validation = new RangeValidation<int>() { MinValue = 1, MaxValue = 6 };
var parameter = new Parameter<int, RangeValidation<int>>();
parameter.Initialize("NumberOfTrays", validation);
parameter.Value = 6;
XElement par = validation.ToXElement<Parameter<int, RangeValidation<int>>>();
I got an exception: Error at reflection of type 'ConfigurableLibray.Parameter'2[System.Int32,ConfigurableLibray.RangeValidation'1[System.Int32]]'
The inner exception says that ConfigurableLibray.Parameter'2[T,V] is not supported
What am I doing wrong?
Thanks in advance for any suggestion!
I solved implementing manually the serialization and deserialization of the classes using reflection.
I need to deserialize
{'Id': 'id123',
'Time': 1436231503,
'Name': 'foo',
'ProductId': 1}
into Container1
public class Container1
{
public CommonFields Common { get; set; }
//fields specific to Container1
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "ProductId")]
public int ProductId { get; set; }
}
and
{
'Id': 'id123',
'Time': 1436231503,
'Group':'10768C21-9971-4D2F-ACD7-10C2EF19FCA8'
}
into Container2
public class Container2
{
public CommonFields Common { get; set; }
//fields specific to Container2
[JsonProperty(PropertyName = "Group")]
public Guid Group { get; set; }
}
using composition (not inheritance). Both JSON have 2 common fields (Id and Time) and specific fields.
With newtonsoft.json
JsonConvert.DeserializeObject<Container1>(json_container1)
the result is that the properties of the 2 container are correctly deserialized. The common properties of the composed classed are not deserialized.
How can I deserialize JSON into C# classes that use only composition?
(using newtonsoft.json is not compulsory)
Below is my attempt.
public class CommonFields
{
[JsonProperty(PropertyName = "Id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "Time")]
public long Time { get; set; }
}
public class Container1
{
public CommonFields Common { get; set; }
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "ProductId")]
public int ProductId { get; set; }
}
public class Container2
{
public CommonFields Common { get; set; }
[JsonProperty(PropertyName = "Group")]
public Guid Group { get; set; }
}
internal class Program
{
private static void Main(string[] args)
{
string json_container1 = #"{
'Id': 'id123',
'Time': 1436231503,
'Name': 'foo',
'ProductId': 1
}";
string json_container2 = #"{
'Id': 'id123',
'Time': 1436231503,
'Group':'10768C21-9971-4D2F-ACD7-10C2EF19FCA8'
}";
var container1Obj = JsonConvert.DeserializeObject<Container1>(json_container1);
var container2Obj = JsonConvert.DeserializeObject<Container2>(json_container2);
Console.ReadKey();
}}}
Don't do it.
The JSON element you deserilize from should not be change, you can remove some properties but it's a bad practice to change its properties structure.
JSON file\content should have a compatible JSON class, if you want to make any changes, make another custom class and make a mapping logic between them.
I think you can just do the deserialize again just on CommonFields of two objects.
container1Obj.Common = JsonConvert.DeserializeObject<CommonFields>(json_container1);
container2Obj.Common = JsonConvert.DeserializeObject<CommonFields>(json_container2);
I know you want to use composition, but I really can't see any pros using composition over inheritance here.
public class BaseClass
{
[JsonProperty(PropertyName = "Id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "Time")]
public long Time { get; set; }
}
public class Container1 : BaseClass
{
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "ProductId")]
public int ProductId { get; set; }
}
public class Container2 : BaseClass
{
[JsonProperty(PropertyName = "Group")]
public Guid Group { get; set; }
}
This is as simple as it can get and should get the job done.
Your question basically the reverse of the question Can I serialize nested properties to my class in one operation with Json.net?, and can be solved with a similar strategy. To simplify things, create an interface for all classes containing common fields:
public interface IHasCommonFields
{
CommonFields Common { get; set; }
}
Then you can create the following generic converter for any type implementing this interface:
public class HasCommonFieldsConverter<T> : JsonConverter where T : IHasCommonFields
{
[ThreadStatic]
static bool disabled;
// Disables the converter in a thread-safe manner.
bool Disabled { get { return disabled; } set { disabled = value; } }
public override bool CanWrite { get { return !Disabled; } }
public override bool CanRead { get { return !Disabled; } }
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var token = JToken.Load(reader);
if (token == null || token.Type == JTokenType.Null)
return null;
using (new PushValue<bool>(true, () => Disabled, val => Disabled = val)) // Prevent infinite recursion of converters
{
var hasCommon = token.ToObject<T>(serializer);
var common = (hasCommon.Common ?? (hasCommon.Common = new CommonFields()));
serializer.Populate(token.CreateReader(), common);
return hasCommon;
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
{
writer.WriteNull();
return;
}
using (new PushValue<bool>(true, () => Disabled, val => Disabled = val)) // Prevent infinite recursion of converters
{
var hasCommon = (T)value;
var obj = JObject.FromObject(hasCommon, serializer);
var common = hasCommon.Common;
if (common != null)
{
var commonObj = JObject.FromObject(common, serializer);
obj.Merge(commonObj);
}
obj.WriteTo(writer);
}
}
}
public struct PushValue<T> : IDisposable
{
Action<T> setValue;
T oldValue;
public PushValue(T value, Func<T> getValue, Action<T> setValue)
{
if (getValue == null || setValue == null)
throw new ArgumentNullException();
this.setValue = setValue;
this.oldValue = getValue();
setValue(value);
}
#region IDisposable Members
// By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
public void Dispose()
{
if (setValue != null)
setValue(oldValue);
}
#endregion
}
Then apply it to all classes implementing IHasCommonFields - and in addition mark the Common property with JsonIgnore:
[JsonConverter(typeof(HasCommonFieldsConverter<Container1>))]
public class Container1 : IHasCommonFields
{
[JsonIgnore]
public CommonFields Common { get; set; }
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "ProductId")]
public int ProductId { get; set; }
}
[JsonConverter(typeof(HasCommonFieldsConverter<Container2>))]
public class Container2 : IHasCommonFields
{
[JsonIgnore]
public CommonFields Common { get; set; }
[JsonProperty(PropertyName = "Group")]
public Guid Group { get; set; }
}
Then, to test:
public class TestClass
{
public static void Test()
{
var container1 = new Container1 { Name = "name", ProductId = 101, Common = new CommonFields { Id = "1401", Time = DateTime.Today.Ticks } };
var container2 = new Container2 { Group = Guid.NewGuid(), Common = new CommonFields { Id = "2401", Time = DateTime.Today.Ticks } };
Test(container1);
Test(container2);
}
private static void Test<T>(T container) where T : class, IHasCommonFields
{
var json = JsonConvert.SerializeObject(container, Formatting.Indented);
Debug.WriteLine(json);
var containerback = JsonConvert.DeserializeObject<T>(json);
var json2 = JsonConvert.SerializeObject(containerback, Formatting.Indented);
Debug.Assert(json == json2); // No assert
if (container.Common != null)
{
Debug.Assert(container.Common.Id == containerback.Common.Id); // No assert
Debug.Assert(container.Common.Time == containerback.Common.Time); // No assert
}
}
}
The JSON created looks like:
{
"Name": "name",
"ProductId": 101,
"Id": "1401",
"Time": 635725152000000000
}
And
{
"Group": "9ed31118-c0b7-4d9f-8f57-303b2e164643",
"Id": "2401",
"Time": 635725152000000000
}
The one disadvantage of this converter is that, if the Common property is null when serialized, it will be deserialized non-null with default values.
If you don't want the IHasCommonFields interface, you could e.g. create an abstract generic base class for your converter with abstract methods to get and set the common fields, then override those methods in each subclass.
(Honestly inheritance does seem simpler than composition here, as other answers have stated.)