JSON serialization with class inherited from List<T> - c#

I have a class that inherits from List<T> and add one more class property
public class DrivenList : List<int>
{
public string Name {get;set;}
private DrivenList() { }
public DrivenList(string name) { this.Nname = name; }
}
When JSON serializing the object using Newtonsoft.Json, I get only the list item. ( [1,2,3] )
Any ideas how to add the Name property to the results?
Solved: by adding this attribute to the list
[JsonObject(MemberSerialization = MemberSerialization.Fields)]
public class DrivenList : List<int>

As far as I know with Newtonsoft all you can do is something like this:
[JsonObject(MemberSerialization = MemberSerialization.Fields)]
public class DrivenList : List<int>
{
[JsonProperty]
public string Name { get; set; }
private DrivenList() { }
public DrivenList(string name) { this.Name = name; }
}
But this will add you unwanted (maybe) fields.
Personally I will do composition instead of inheritance:
public class DrivenList
{
public string Name { get; set; }
public List<int> Items { get; set; }
private DrivenList() { }
public DrivenList(string name) { this.Name = name; }
}

What .NET version are you using and what serializer?
If you are using the standard serializer, then adding [DataMember] annotations would be the answer.
https://msdn.microsoft.com/en-us/library/bb412179(v=vs.110).aspx
But I would suggest to use Json.NET http://www.newtonsoft.com/json
Update:
I would suggest not to directly inherit to List
class Program
{
static void Main(string[] args)
{
var list = new Driven("Ragnarok");
list.Items.Add(1);
list.Items.Add(2);
string json = JsonConvert.SerializeObject(list);
Console.WriteLine(json);
Console.ReadKey();
}
}
public class Driven
{
public Driven(string name)
{
this.Name = name;
}
public List<int> Items { get; set; } = new List<int>();
public string Name { get; set; }
}
Output:
{"Items":[1,2],"Name":"Ragnarok"}

An alternative solution could be to delegate the implementation of IList to your own property. Then you can use the DataContractSerializer. The upside of this is that all the existing C#-code (and all your tests) will still be intact, and no custom logic is needed for serializing it.
If that's not an option and you really want to use NewtonSoft, then you should take a look at this answer, and create your own JsonConverter.
How to serialize/deserialize a custom collection with additional properties using Json.Net
The problem is the following: when an object implements IEnumerable,
JSON.net identifies it as an array of values and serializes it
following the array Json syntax (that does not include properties)
Here's an example that use DataContractSerializer:
JsonHelper from CodeProject
public class JsonHelper
{
/// <summary>
/// JSON Serialization
/// </summary>
public static string JsonSerializer<T>(T t)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
MemoryStream ms = new MemoryStream();
ser.WriteObject(ms, t);
string jsonString = Encoding.UTF8.GetString(ms.ToArray());
ms.Close();
return jsonString;
}
/// <summary>
/// JSON Deserialization
/// </summary>
public static T JsonDeserialize<T>(string jsonString)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
T obj = (T)ser.ReadObject(ms);
return obj;
}
}
And the new implementation of your class.
[DataContract]
public class DrivenList : IList<int>
{
[DataMember]
public List<int> Items = new List<int>();
[DataMember]
public string Name { get; set; }
private DrivenList() { }
public DrivenList(string name) { this.Name = name; }
#region Implementation of IList
public IEnumerator<int> GetEnumerator()
{
return Items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)Items).GetEnumerator();
}
public void Add(int item)
{
Items.Add(item);
}
public void Clear()
{
Items.Clear();
}
public bool Contains(int item)
{
return Items.Contains(item);
}
public void CopyTo(int[] array, int arrayIndex)
{
Items.CopyTo(array, arrayIndex);
}
public bool Remove(int item)
{
return Items.Remove(item);
}
public int Count
{
get { return Items.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public int IndexOf(int item)
{
return Items.IndexOf(item);
}
public void Insert(int index, int item)
{
Items.Insert(index, item);
}
public void RemoveAt(int index)
{
Items.RemoveAt(index);
}
public int this[int index]
{
get { return Items[index]; }
set { Items[index] = value; }
}
#endregion
}
And an example usage:
var list = new DrivenList("foo");
list.Add(1);
list.Add(3);
list.Add(5);
var json = JsonHelper.JsonSerializer(list);
Output:
{"Items":[1,3,5],"Name":"foo"}

Apply the DataContract attribute for the class and DataMember attribute for the properties.
[DataContract]
public class DrivenList : List<int>
{
[DataMember]
public string Name {get;set;}
private DrivenList() { }
public DrivenList(string name) { this.Nname = name; }
}

Related

How do I serialize a class to a string?

How to serialize the OrganizationType class?
No additional properties - wrappers.
public class INNType : IConvertToString
{
protected INNType() { }
public string Value { get; }
public INNType(string inn)
{
if (!Regex.IsMatch(inn, #"^\d{10}$")) throw new Exception(#"");
Value = inn;
}
public override string ToString() => Value;
public static implicit operator INNType(string inn) => new INNType(inn);
public static implicit operator string(INNType inn) => inn?.Value;
}
[Serializable]
[XmlType(Namespace = "http://roskazna.ru/gisgmp/xsd/Organization/2.2.0")]
public class OrganizationType
{
protected OrganizationType() {}
[XmlAttribute("inn")]
public INNType Inn {get; set;}
}
After serialization, it should look like below.
<OrganizationType inn="1234567890" />
The method used to serialize objects looks like this
public static XmlDocument SerializerObject<T>(T obj, XmlSerializerNamespaces xsn) where T : class
{
XmlDocument xmlDocument = new XmlDocument();
using (var xs = xmlDocument.CreateNavigator().AppendChild())
{
new XmlSerializer(typeof(T)).Serialize(xs, obj, xsn);
}
return xmlDocument;
}
Exception
System.InvalidOperationException : Cannot serialize member 'Inn' of type GisGmp.INNType. XmlAttribute/XmlText cannot be used to encode complex types.
I have to do it. Not good.
[XmlIgnore]
public INNType Inn {get; set;}
[XmlAttribute("inn")]
public string WrapperInn { get => Inn; set => Inn = value; }
You could implement IXmlSerializable:
[Serializable]
public class OrganizationType : IXmlSerializable
{
public OrganizationType()
{
// Demo
this.Inn = new INNType("0123456789");
}
[XmlAttribute("inn")]
public INNType Inn { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
return;
}
public void WriteXml(XmlWriter writer)
{
writer.WriteAttributeString("inn", this.Inn.Value);
}
}
Output:
<OrganizationType inn="0123456789" />

How to serialize class as attribute?

I am trying to serialize a class as an attribute. Here's the use case: I need to store a large number of engineering parameters in an xml config file. Scientific notation is involved, and it is required by the customer that the entered values remain in the exact form the user entered them. For example, if someone enters "5.3e-1" then it must remain like that, and cannot be converted into, say, "0.53". To this end I've created a Params class that stores both the entered string and double values (actually storing the double values is only for processing efficiency later). Now here's the trick: I only want the string value to be serialized, and I want that to serialize as an attribute.
For example, if an object contains two parameters, A and B, where the string values are A.stringVal = "1.2e5" and B.stringVal = "2.0" then I would like:
public class MyObject
{
[XmlAttribute]
public MyParam A { get; set; }
[XmlAttribute]
public MyParam B { get; set; }
...more stuff...
}
to serialize to:
<myObject A="1.2e5" B="2.0">
more stuff...
</myObject>
My question is very similar to one asked here. Unlike him I am fine with implementing IXmlSerializable (and would prefer to), I just can't make it work. When I try to serialize it I get a cryptic exception saying, "There was error reflection type." What am I doing wrong?
public class MyParam : IXmlSerializable
{
string name;
string stringVal;
double doubleVal;
public string Val
{
get
{
return stringVal;
}
set
{
stringVal = value;
doubleVal = double.Parse(value);
}
}
public double DoubleVal
{
get
{
return doubleVal;
}
set
{
doubleVal = value;
stringVal = value.ToString();
}
}
public MyParam(string name)
{
this.name = name;
this.stringVal = string.Empty;
this.doubleVal = double.NaN;
}
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
throw new NotImplementedException();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteAttributeString(name, stringVal);
}
}
To get what you want you need to control the serialization on the container that holds the properties, not the property itself. You can still encapsulate the serialization code in the property however, see below.
public class MyObject : IXmlSerializable
{
public MyParam A { get; set; }
public MyParam B { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
throw new NotImplementedException();
}
public void WriteXml(XmlWriter writer)
{
//Call each properties "WriteAttribute" call.
A.WriteAttribute(writer);
B.WriteAttribute(writer);
}
}
public class MyParam
{
string name;
string stringVal;
double doubleVal;
public string Val
{
get
{
return stringVal;
}
set
{
stringVal = value;
doubleVal = double.Parse(value);
}
}
public double DoubleVal
{
get
{
return doubleVal;
}
set
{
doubleVal = value;
stringVal = value.ToString();
}
}
public MyParam(string name)
{
this.name = name;
this.stringVal = string.Empty;
this.doubleVal = double.NaN;
}
internal void WriteAttribute(XmlWriter writer)
{
writer.WriteAttributeString(name, stringVal);
}
}
class Program
{
static void Main(string[] args)
{
var test = new MyObject()
{
A = new MyParam("A"),
B = new MyParam("B"),
};
test.A.Val = "1.2e5";
test.B.Val = "2.0";
var ser = new XmlSerializer(typeof(MyObject));
var sb = new StringBuilder();
using (var stream = new StringWriter(sb))
{
ser.Serialize(stream, test);
}
Console.WriteLine(sb);
Console.ReadLine();
}
}
Outputs
<?xml version="1.0" encoding="utf-16"?>
<MyObject A="1.2e5" B="2.0" />
If you don't need the name of the property in the property itself you can modify the code to the following.
public class MyObject : IXmlSerializable
{
//....
public void WriteXml(XmlWriter writer)
{
//Call each properties "WriteAttribute" call.
A.WriteAttribute(writer, "A");
B.WriteAttribute(writer, "B");
}
}
public class MyParam
{
//...
public MyParam()
{
this.stringVal = string.Empty;
this.doubleVal = double.NaN;
}
internal void WriteAttribute(XmlWriter writer, string name)
{
writer.WriteAttributeString(name, stringVal);
}
}
After I've added the parameterless constructor, I got the following exception:
The element 'A' type ConsoleApplication1.MyParam can not be serialized. XmlAttribute / XmlText can not be used to encode types that implement IXmlSerializable.
After removing IXmlSerializable I got an exception XmlAttribute/XmlText cannot be used to encode complex types. And found this answer
and this.
So, I think, it is better to find another way to serialize attributes.

XmlSerializer putting element name inside a property when deserializing

I have an issue with the .NET XML Serializer where I have do different XML Elements with different names that map to the same type. Basically, the objects should be exactly the same, but I want them to have a string or enum or something that identifies which of the three possible element names were used. So here's an example:
<Body>
<MyTypeA>
<Foo>bar</Foo>
</MyTypeA>
<MyTypeB>
<Foo>bar</Foo>
</MyTypeB>
</Body>
Now, for the classes, MyTypeA and MyTypeB will both be the same type. For example:
public class Body {
public MyType MyTypeA { get; set; }
public MyType MyTypeB { get; set; }
}
public class MyType {
public string Foo { get; set; }
[XmlIgnore]
public MyTypeType { get; set; }
}
public enum MyTypeType
{
MyTypeA,
MyTypeB
}
When serializing it works fine, because I can always just ensure one way or another that the enum is set properly before serializing. But when deserializing it is not getting set and I'm not sure there's a way how.
For the record, I unfortunately don't get to set the schema, otherwise I would have built it in such a way that I didn't have this problem.
If i understood your question correctly, this might help you. Just write you XML file path on the 4th line and try it.
namespace ConsoleApplication1
{
class Program
{
//private const string xmlPath = #"C:\Users\Jumast\Desktop\StackOverflowQuestion.xml";
private const string xmlPath, // put the file path here
static Body makeBody()
{
var instance1 = new MyType() { Category = Category.MyTypeA, Foo = "bar" };
var instance2 = new MyType() { Category = Category.MyTypeB, Foo = "bar" };
return new Body(){Instance1 = instance1, Instance2 = instance2};
}
static void serializeBody(Body body, string path)
{
var ser = new DataContractSerializer(body.GetType(), body.GetType().Name, "");
using (var w = XmlWriter.Create(path, new XmlWriterSettings() { Indent = true }))
{
ser.WriteObject(w, body);
}
}
static Body deseerializeBody(string xmlPath)
{
Body deserializedBody;
var ser = new XmlSerializer(typeof(Body));
using (Stream stream = File.OpenRead(xmlPath))
{
deserializedBody = (Body)ser.Deserialize(stream);
}
return deserializedBody;
}
static void writeBodyToConsole(Body body)
{
Console.WriteLine("Instance1: " + body.Instance1);
Console.WriteLine("Instance2: " + body.Instance2);
Console.ReadKey();
}
static void Main(string[] args)
{
serializeBody(makeBody(), xmlPath);
writeBodyToConsole(deseerializeBody(xmlPath));
}
}
public class Body : IXmlSerializable
{
#region Properties
public MyType Instance1 { get; set; }
public MyType Instance2 { get; set; }
#endregion
#region IXmlSerializable
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
reader.ReadStartElement();
Instance1 = new MyType(reader);
Instance2 = new MyType(reader);
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
Instance1.WriteXml(writer);
Instance2.WriteXml(writer);
}
#endregion
}
public class MyType : IXmlSerializable
{
#region Fields
private Category _category;
#endregion
#region Constructors
public MyType()
{
_category = Category.nil;
Foo = string.Empty;
}
public MyType(XmlReader reader) { ReadXml(reader);}
#endregion
#region Methods
public override string ToString()
{
var sb = new StringBuilder();
sb.Append(string.Format("Foo = {0}", Foo));
sb.Append(" , ");
sb.Append(string.Format("Category = {0}", Category));
return sb.ToString();
}
#endregion
#region Properties
public string Foo { get; set; }
public Category Category
{
get { return this._category; }
set { this._category = value; }
}
#endregion
#region IXmlSerializable
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
Enum.TryParse(reader.Name, out _category);
reader.Read();
Foo = reader.ReadElementContentAsString("Foo", "");
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteStartElement(this.Category.ToString(), "");
writer.WriteElementString("Foo", Foo);
writer.WriteEndElement();
}
#endregion
}
public enum Category
{
MyTypeA,
MyTypeB,
nil
}
}

XML Serialization on a custom data

I have a XML file:
<Hand cards="C5,SQ,DQ,H8,C9,H7,S9,D5,DA,CJ,S6,HK,D4">
</Hand>
I define a class
[Serializable()]
[XmlRoot("Hand")]
public class Hand
{
[XmlAttribute("cards")]
public List<string> Cards{get;set;}
}
How to deserialize a XML to object in this case? Hand object result must have Cards = {C5,SQ,DQ,H8,C9,H7,S9,D5,DA,CJ,S6,HK,D4}.
You cannot.
What you can do is to create a property which will do this conversion in its getter/setter
[XmlIgnore]
public List<string> CardList { get; private set; }
[XmlAttribute("cards")]
public string Cards {
get { return String.Join(",", CardList); }
set { CardList = value.Split(",").ToList(); }
}
You can do this with the help of IXmlSerializable. Read more about it on MSDN.
This way
[Serializable()]
[XmlRoot("Hand")]
public class Hand : IXmlSerializable {
[XmlAttribute("cards")]
public List<string> Cards { get; set; }
public System.Xml.Schema.XmlSchema GetSchema() { return null; }
public void ReadXml(XmlReader reader) {
this.Cards = new List<string>(reader.GetAttribute("cards").Split(','));
}
public void WriteXml(XmlWriter writer) {
writer.WriteAttributeString("cards",
string.Join(",",
this.Cards != null ? this.Cards : new List<string>()));
}
}
Hope this helps you.

C# Casting and Generics

I've been struggling with a piece of C# code and although I have found a solution to the problem, it is by no means ideal (see DoSomething_WorksButNotIdeal() below).
What I would like to do is instead of having the if, else statement (which is potentially massive depending on what types I want to support) just have a generic cast, but I can't get it to work. I've tried to demonstrate this in the DoSomething_HelpMe() method.
Is there anyway of achieving this? Any help is greatly appreciated.
public interface ITag
{
string TagName { get; }
Type Type { get; }
}
public interface ITag<T> : ITag
{
T InMemValue { get; set; }
T OnDiscValue { get; set; }
}
public class Tag<T> : ITag<T>
{
public Tag(string tagName)
{
TagName = tagName;
}
public string TagName { get; private set; }
public T InMemValue { get; set; }
public T OnDiscValue { get; set; }
public Type Type{ get{ return typeof(T);} }
}
public class MusicTrack
{
public MusicTrack()
{
TrackTitle = new Tag<string>("TrackTitle");
TrackNumber = new Tag<int>("TrackNumber");
Tags = new Dictionary<string, ITag>();
Tags.Add(TrackTitle.TagName, TrackTitle);
Tags.Add(TrackNumber.TagName, TrackNumber);
}
public IDictionary<string,ITag> Tags;
public ITag<string> TrackTitle { get; set; }
public ITag<int> TrackNumber { get; set; }
}
public static class Main
{
public static void DoSomething_WorksButNotIdeal()
{
MusicTrack track1 = new MusicTrack();
MusicTrack track2 = new MusicTrack();
// Set some values on the tracks
foreach (ITag tag in track1.Tags.Values)
{
Type type = tag.Type;
if (type == typeof(string))
{
((ITag<string>) tag).InMemValue = ((ITag<string>)track2.Tags[tag.TagName]).OnDiscValue;
}
else if (type == typeof(int))
{
((ITag<int>)tag).InMemValue = ((ITag<int>)track2.Tags[tag.TagName]).OnDiscValue;
}
else if (type == typeof(bool))
{
((ITag<bool>)tag).InMemValue = ((ITag<bool>)track2.Tags[tag.TagName]).OnDiscValue;
}
// etc etc
else
{
throw new Exception("Unsupported type.");
}
}
}
public static void DoSomething_HelpMe()
{
MusicTrack track1 = new MusicTrack();
MusicTrack track2 = new MusicTrack();
// Set some values on the tracks
foreach (ITag tag in track1.Tags.Values)
{
Type type = tag.Type;
// THIS OBVIOUSLY DOESN'T WORK BUT I'M JUST TRYING TO DEMONSTRATE WHAT
// I'D IDEALLY LIKE TO ACHIEVE
((ITag<typeof(type)>)tag).InMemValue = ((ITag<typeof(type)>)track2.Tags[tag.TagName]).OnDiscValue;
}
}
}
Any reason that you can't have:
public interface ITag
{
string TagName { get; }
Type Type { get; }
object InMemValue { get; set; }
object OnDiscValue { get; set; }
}
and use ITag<T> to make it more specific?
public interface ITag<T> : ITag
{
new T InMemValue { get; set; }
new T OnDiscValue { get; set; }
}
Then your method can just use ITag. You'd need something like (int Tag<T>):
object ITag.InMemValue
{
get { return InMemValue; }
set { InMemValue = (T)value; }
}
object ITag.OnDiscValue
{
get { return OnDiscValue; }
set { OnDiscValue = (T)value; }
}
(edit)
Another option would be a method on the non-generic ITag:
void CopyValueFrom(ITag tag);
(maybe a bit more specific about what it copies to/from)
Your concrete implementation (Tag<T>) would have to assume that the ITag is actually an ITag<T> and cast:
public void CopyFromTag(ITag tag) {
ITag<T> from = tag as ITag<T>;
if(from==null) throw new ArgumentException("tag");
this.TheFirstProperty = from.TheSecondProperty;
}
The simplest way to solve it is to resolve the type where you have the information, namely inside the Tag<T> implementation, so add the following to your existing types (only showing the additions!)
public interface ITag
{
void CopyFrom(bool sourceIsMem, ITag sourceTag, bool targetIsMem);
}
public class Tag<T> : ITag<T>
{
public void CopyFrom(bool sourceIsMem, ITag sourceTag, bool targetIsMem)
{
ITag<T> castSource = sourceTag as ITag<T>;
if (castSource == null)
throw new ArgumentException(
"Source tag is of an incompatible type", "sourceTag");
if (targetIsMem)
InMemValue = sourceIsMem ?
castSource.InMemValue : castSource.OnDiscValue;
else
OnDiscValue = sourceIsMem ?
castSource.InMemValue : castSource.OnDiscValue;
}
}
Note that you really should use enum types for the sourceIsMem and targetIsMem instead, because a bool is really ugly and hard to read in the invocation as the following fragment will show.
This is how you would make your routine work now:
public static void DoSomething_HelpMe()
{
MusicTrack track1 = new MusicTrack();
MusicTrack track2 = new MusicTrack();
// Set some values on the tracks
foreach (ITag tag in track1.Tags.Values)
tag.CopyFrom(false, track2.Tags[tag.TagName], true);
}
Here's one approach, which requires a decent amount of boilerplate but will allow you to do what you want using your existing definitions of ITag, ITag<T>, and Tag<T>. The TagSetter class sets the in memory value from the on disc value in a type safe way for any ITag<T>.
/// <summary>
/// Allows a tag of any type to be used to get a result of type TResult
/// </summary>
/// <typeparam name="TResult">The result type after using the tag</typeparam>
public interface ITagUser<TResult>
{
TResult Use<T>(ITag<T> tag);
}
/// <summary>
/// Allows a tag of any type to be used (with no return value)
/// </summary>
public interface ITagUser
{
void Use<T>(ITag<T> tag);
}
/// <summary>
/// Wraps a tag of some unknown type. Allows tag users (either with or without return values) to use the wrapped list.
/// </summary>
public interface IExistsTag
{
TResult Apply<TResult>(ITagUser<TResult> user);
void Apply(ITagUser user);
}
/// <summary>
/// Wraps a tag of type T, hiding the type itself.
/// </summary>
/// <typeparam name="T">The type of element contained in the tag</typeparam>
class ExistsTag<T> : IExistsTag
{
ITag<T> tag;
public ExistsTag(ITag<T> tag)
{
this.tag = tag;
}
#region IExistsTag Members
public TResult Apply<TResult>(ITagUser<TResult> user)
{
return user.Use(tag);
}
public void Apply(ITagUser user)
{
user.Use(tag);
}
#endregion
}
public interface ITag
{
string TagName { get; }
Type Type { get; }
}
public interface ITag<T> : ITag
{
T InMemValue { get; set; }
T OnDiscValue { get; set; }
}
public class Tag<T> : ITag<T>
{
public Tag(string tagName)
{
TagName = tagName;
}
public string TagName { get; private set; }
public T InMemValue { get; set; }
public T OnDiscValue { get; set; }
public Type Type { get { return typeof(T); } }
}
public class TagSetter : ITagUser
{
#region ITagUser Members
public void Use<T>(ITag<T> tag)
{
tag.InMemValue = tag.OnDiscValue;
}
#endregion
}
public class TagExtractor : ITagUser<ITag>
{
#region ITagUser<ITag> Members
public ITag Use<T>(ITag<T> tag)
{
return tag;
}
#endregion
}
public class MusicTrack
{
public MusicTrack()
{
TrackTitle = new Tag<string>("TrackTitle");
TrackNumber = new Tag<int>("TrackNumber");
Tags = new Dictionary<string, IExistsTag>();
Tags.Add(TrackTitle.TagName, new ExistsTag<string>(TrackTitle));
Tags.Add(TrackNumber.TagName, new ExistsTag<int>(TrackNumber));
}
public IDictionary<string, IExistsTag> Tags;
public ITag<string> TrackTitle { get; set; }
public ITag<int> TrackNumber { get; set; }
}
public static class Main
{
public static void DoSomething_WorksButNotIdeal()
{
MusicTrack track1 = new MusicTrack();
MusicTrack track2 = new MusicTrack();
TagSetter setter = new TagSetter();
TagExtractor extractor = new TagExtractor();
// Set some values on the tracks
foreach (IExistsTag tag in track1.Tags.Values)
{
tag.Apply(setter);
// do stuff using base interface if necessary
ITag itag = tag.Apply(extractor);
}
}
}

Categories