I'm wondering if I can get Nancy to auto bind a request to a subclass of the type I specify in the type parameters. Here's an example of what I'm trying to achieve:
Given these classes:
public class Shape
{
public int Height { get; set; }
public int Width { get; set; }
}
public class Triangle : Shape
{
public string SomeTriangleOnlyProp { get; set; }
}
public class Square : Shape
{
public string SomeSquareOnlyProp { get; set; }
}
Then given this Json:
{
"Height" : 10,
"Width" : 20
}
Then this is my desired result:
var shape = this.Bind<Shape>(); //Returns a Shape object
Given this Json:
{
"Height" : 10,
"Width" : 20,
"SomeTriangleOnlyProp" : "Triangle"
}
Then this is my desired result:
var shape = this.Bind<Shape>(); //Returns a Triangle object
Given this Json:
{
"Height" : 10,
"Width" : 20,
"SomeSquareOnlyProp" : "Square"
}
Then this is my desired result:
var shape = this.Bind<Shape>(); //Returns a Square object
Could I only achieve this with a custom binding class? I could try to bind to each type separately and handle any errors but that seems really unoptimal.
I've found a solution, I'm not sure if it's the best one but it's working how I need it so it's what I'll go with for now. I've written a custom model binder that looks at the json to try and determine what object it should serialize to:
public class ShapeBinder : IModelBinder
{
public object Bind(NancyContext context, Type modelType, object instance, BindingConfig configuration, params string[] blackList)
{
using (var sr = new StreamReader(context.Request.Body))
{
var json = sr.ReadToEnd();
if (json.Contains("SomeTriangleOnlyProp"))
{
var triangle = new Nancy.Json.JavaScriptSerializer().Deserialize<Triangle>(json);
return triangle;
}
else if (json.Contains("SomeSquareOnlyProp"))
{
var square = new Nancy.Json.JavaScriptSerializer().Deserialize<Square>(json);
return square;
}
else
{
var shape = new Nancy.Json.JavaScriptSerializer().Deserialize<Shape>(json);
return shape;
}
}
}
public bool CanBind(Type modelType)
{
return modelType == typeof(Shape);
}
}
Calling this in the NancyModule with var shape = this.Bind<Shape>(); returns a Triangle if the JSON had the triangle prop, a Square if the JSON had the square prop, or just the regular base Shape class if the JSON had neither.
Related
I want to serialize objects using json.net and C# .Also I want only selected properties to be inside the final JSON object returned. I have two classes
public class EmployeeClass {
[JsonProperty("className")]
public string Name{ get; set;}
[JsonProperty("hierUnitId")]
public int? HierUnitId { get; set; }
[JsonProperty("rvcOperatorOptions")]
public List<OperatorOptions> RvcOperatorOptions{get; set;}
}
public class OperatorOptions{
[JsonProperty("rvcObjNum")]
public int? RvcObjectNum {get; set;}
[JsonProperty("options")]
public string Options {get; set;}
}
Now I have an EmployeeClass object which I want to serialize.
{
"className" : "EmpClass",
"hierUnitId" : 101,
"rvcOperatorOptions" : [
{ "rvcObjNum" : 10 , "options" : "00010011" } ,
{ "rvcObjNum" : 11 , "options" : "11110011" }
]
}
For that i have override the CreateProperties method of the DefaultContractResolver class for including only selected properties.Also i'm passing the list of properties to be included to the constructor of my CustomRetrieveResponseResolver class which is extending DefaultContractResolver.
private readonly IList<string> _propertiesToInclude;
public CustomRetrieveResponseResolver(IList<string> propertiesToInclude)
{
_propertiesToInclude = propertiesToInclude;
}
I have a list of strings propertiesToInclude which have the name of properties to be included.
For ex:
propertiesToInclude = { "Name" , "RvcOperatorOptions.RvcObjectNum" }
Now the problem is that in the list propertiesToInclude i have the relative names of the nested properties. I know that CreateProperties is going to be called twice one for EmployeeClass and then for OperatorOptions Class ( due to the List<OperatorOptions> RvcOperatorOptions inside EmployeeClass ). Is there any way of serializing in this manner ? Like the output for the above object will be
{
"className" : "EmpClass",
"rvcOperatorOptions" : [
{ "rvcObjNum" : 10 } ,
{ "rvcObjNum" : 11 }
]
}
Can Someone help me in this i.e serializing selected values with the using path of nested properties?
Use [JsonIgnore] attribute if you want to ignore properties when serializing/reserializing.
For dynamic exclusion on properties:
public class CustomPropertiesContractResolver : DefaultContractResolver
{
private HashSet<string> _propertySet;
public CustomPropertiesContractResolver(IEnumerable<string> propertyNames)
{
if (propertyNames != null)
{
_propertySet = new HashSet<string>(propertyNames, StringComparer.OrdinalIgnoreCase);
}
}
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
List<MemberInfo> serializableMembers = null;
var allMembers = base.GetSerializableMembers(objectType);
if (_propertySet != null && _propertySet.Count > 0)
{
serializableMembers = allMembers.Where(m => !_propertySet.Contains(m.Name)).ToList();
}
return serializableMembers != null && serializableMembers.Count > 0 ? serializableMembers : allMembers;
}
}
Usage
var serializedStr = JsonConvert.SerializeObject(employeeObj, new JsonSerializerSettings()
{
ContractResolver = new CustomPropertiesContractResolver(new List<string>{"options"})
};);
To provide depth and be able to track contracts of nested properties, check this answer: Json.NET serialize by depth and attribute
Is there a way to disable completely (for all classes) the discriminator ("_t") fields from being added to the bson documents?
I am referring to: mongo-csharp-driver/polymorphism
Let's say we have a Square and Rectangle that inherit from Shape.
public abstract class Shape
{
public ObjectId Id { get; set; }
}
public sealed class Square : Shape
{
public int Size { get; set; }
}
public sealed class Rectangle : Shape
{
public int Width { get; set; }
public int Height { get; set; }
}
Like you said if we run the following code.
var client = new MongoClient();
var db = client.GetDatabase("test");
var shapes = db.GetCollection<Shape>("shapes");
await shapes.InsertManyAsync(new Shape[]
{
new Square{Size = 10},
new Rectangle{Height = 5, Width = 4}
});
We'll get the following inserted into MongoDB
db.shapes.find()
{ "_id" : ObjectId("5f4e2affc23dde5a501bdf0b"), "_t" : "Square", "Size" : 10 }
{ "_id" : ObjectId("5f4e2affc23dde5a501bdf0c"), "_t" : "Rectangle", "Width" : 4, "Height" : 5 }
Initially, I thought we'd be able to set the DiscriminatorIsRequired flag on the BsonClassMap and wrap that in a convention, however, from trying this it seems to fail due to the following bit of logic in the MongoDB C# Driver.
private bool ShouldSerializeDiscriminator(Type nominalType)
{
return (nominalType != _classMap.ClassType || _classMap.DiscriminatorIsRequired || _classMap.HasRootClass) && !_classMap.IsAnonymous;
}
https://github.com/mongodb/mongo-csharp-driver/blob/9e567e23615c8bb5c7ac1489427c2d15b2124522/src/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs#L722
So because there's no way for us to tell the serializer we don't want to include a discriminator we'll have to give it a convention instead that does nothing.
If we create an IDiscriminatorConvention that pretty much does nothing and returns back null for the discriminator then the driver won't add this to the document.
public class NullDiscriminatorConvention : IDiscriminatorConvention
{
public static NullDiscriminatorConvention Instance { get; }
= new NullDiscriminatorConvention();
public Type GetActualType(IBsonReader bsonReader, Type nominalType)
=> nominalType;
public BsonValue GetDiscriminator(Type nominalType, Type actualType)
=> null;
public string ElementName { get; } = null;
}
This discriminator convention then needs to be registered against each type.
BsonSerializer.RegisterDiscriminatorConvention(typeof(Square), NullDiscriminatorConvention.Instance);
BsonSerializer.RegisterDiscriminatorConvention(typeof(Rectangle), NullDiscriminatorConvention.Instance);
Alternately if we want it on all types you could do a little bit of reflection.
var shapeTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(domainAssembly => domainAssembly.GetTypes(),
(domainAssembly, assemblyType) => new {domainAssembly, assemblyType})
.Where(t => #t.assemblyType.IsSubclassOf(typeof(Shape)))
.Select(t => #t.assemblyType).ToArray();
foreach (var shapeType in shapeTypes)
{
BsonSerializer.RegisterDiscriminatorConvention(shapeType, NullDiscriminatorConvention.Instance);
}
Now if we re-run our code.
var shapeTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(domainAssembly => domainAssembly.GetTypes(),
(domainAssembly, assemblyType) => new {domainAssembly, assemblyType})
.Where(t => #t.assemblyType.IsSubclassOf(typeof(Shape)))
.Select(t => #t.assemblyType).ToArray();
foreach (var shapeType in shapeTypes)
{
BsonSerializer.RegisterDiscriminatorConvention(shapeType, NullDiscriminatorConvention.Instance);
}
var client = new MongoClient();
var db = client.GetDatabase("test");
var shapes = db.GetCollection<Shape>("shapes");
await shapes.InsertManyAsync(new Shape[]
{
new Square{Size = 10},
new Rectangle{Height = 5, Width = 4}
});
we'll get our expected output.
db.shapes.find()
{ "_id" : ObjectId("5f4e2d63ed12d7c5d3638d36"), "Size" : 10 }
{ "_id" : ObjectId("5f4e2d63ed12d7c5d3638d37"), "Width" : 4, "Height" : 5 }
One option is using Newtonsoft bson serializer (Newtonsoft.Json.Bson) which gives a lot of serialization options.
It isn't efficient since you need to write the bson to a stream and then read it from there with MongoDb reader but it provides lots of customization option.
Example code:
class BsonDocBuilder
{
private readonly MemoryStream _memStream = new MemoryStream();
private readonly JsonSerializerSettings _serializeSettings = new JsonSerializerSettings();
private readonly JsonSerializer _jsonSerializer;
public BsonDocBuilder()
{
_jsonSerializer = JsonSerializer.Create(_serializeSettings);
}
public BsonDocument ToBson<T>(T value)
{
BsonDocument bd;
try
{
using (BsonDataWriter dataWriter = new BsonDataWriter(_memStream))
{
dataWriter.CloseOutput = false;
_jsonSerializer.Serialize(dataWriter, value);
}
bd= BsonSerializer.Deserialize<BsonDocument>(_memStream.ToArray());
}
finally
{
_memStream.SetLength(0);
}
return bd;
}
}
Ive come across multiple questions and answers on here but none specific to my situation.
I have a class 'Entity' with multiple classes that extend off of it. I want the serialization to hit the list and understand and use the type of each item for the node name.
Now, I can use what is commented out (define each array item in the main class and define the name of such by using [XmlArrayItem("Subclass1", typeof(subclass1)] but I want to keep all definitions in their subclass and I will be having too many subclasses to define everything in the main entity class...Is there anyway to achieve this?
I have tried using [XmlType(TypeName="...")] for the subclasses and so on but that did not work.
[Serializable]
[XmlInclude(typeof(Subclass1))]
[XmlRoot("Entity")]
public class Entity{
[XmlArray("CausedBy")]
//[XmlArrayItem("Subclass1", typeof(subclass1))]
//[XmlArrayItem("Sublcass2", typeof(Subclass2))]
public List<Entity> CausedBy { get; set; }
}
[Serializable]
[XmlRoot("Subclass1")]
[XmlInclude(typeof(Subclass2))]
public class Subclass1:Entity{
//Code...
}
[Serializable]
[XmlRoot("Subclass2")]
public class Subclass2:Subclass1{
//Code...
}
Serializing the above code after creating an entity and adding a Subclass1 and Subclass2 to the list 'CausedBy' class results in the following:
<Entity>
<CausedBy>
<Entity ... xsi:type="SubClass1" />
<Entity ... xsi:type="SubClass2" />
</CausedBy>
<Entity>
I would like the output to show:
<Entity>
<CausedBy>
<SubClass1 .../>
<SubClass2 .../>
</CausedBy>
<Entity>
Since I totally failed to read the question to begin with, here's a new answer (it's a bit of a tl;dr, so you can always skip to the end and follow the link):
It isn't possible to get the built in serializer class to work because you don't wish to add the attributes that it needs to be able to operate. Your only option is to seralize the class yourself, however, this need not be as tedious as it sounds; I had a similar issue a few years ago with DataGridView in virtual mode and produced a generic virtualizer that could be used to virtualize the data for display; it used a custom attribute:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class showColumnAttribute : System.Attribute
{
///<summary>Optional display format for column</summary>
public string Format;
///<summary>Optional Header string for column<para>Defaults to propety name</para></summary>
public string Title;
///<summary>Optional column edit flag - defaults to false</summary>
public bool ReadOnly;
///<summary>Optional column width</summary>
public int Width;
///<summary>
///Marks public properties that are to be displayed in columns
///</summary>
public showColumnAttribute()
{
Format = String.Empty;
Title = String.Empty;
ReadOnly = false;
Width = 0;
}
}
And a constructor:
///<summary>
///Extracts the properties of the supplied type that are to be displayed
///<para>The type must be a class or an InvalidOperationException will be thrown</para>
///</summary>
public Virtualiser(Type t)
{
if (!t.IsClass)
throw new InvalidOperationException("Supplied type is not a class");
List<VirtualColumnInfo> definedColumns = new List<VirtualColumnInfo>();
PropertyInfo[] ps = t.GetProperties();
MethodInfo mg, ms;
for (int i = 0; i < ps.Length; i++)
{
Object[] attr = ps[i].GetCustomAttributes(true);
if (attr.Length > 0)
{
foreach (var a in attr)
{
showColumnAttribute ca = a as showColumnAttribute;
if (ca != null)
{
mg = ps[i].GetGetMethod();
if (mg != null)
{
ms = ps[i].GetSetMethod();
definedColumns.Add
(
new VirtualColumnInfo
(
ps[i].Name, ca.Width, ca.ReadOnly, ca.Title == String.Empty ? ps[i].Name : ca.Title,
ca.Format, mg, ms
)
);
}
break;
}
}
}
}
if (definedColumns.Count > 0)
columns = definedColumns.ToArray();
}
This extracts the public properties of the class and supplies marked items to the DataGridView as columns together with a header, format, etc.
The effect of all of this (and the rest of the missing code) was that any type could be virtualized in a dataGridView simply by tagging public properties and calling the virtualizer once for a given type:
#region Virtualisation
static readonly Virtualiser Virtual = new Virtualiser(typeof(UserRecord));
[XmlIgnore] // just in case!
public static int ColumnCount { get { return Virtual.ColumnCount; } }
public static VirtualColumnInfo ColumnInfo(int column)
{
return Virtual.ColumnInfo(column);
}
public Object GetItem(int column)
{
return Virtual.GetItem(column, this);
}
/*
** The supplied item should be a string - it is up to this method to supply a valid value to the property
** setter (this is the simplest place to determine what this is and how it can be derived from a string).
*/
public void SetItem(int column, Object item)
{
String v = item as String;
int t = 0;
if (v == null)
return;
switch (Virtual.GetColumnPropertyName(column))
{
case "DisplayNumber":
if (!int.TryParse(v, out t))
t = 0;
item = t;
break;
}
try
{
Virtual.SetItem(column, this, item);
}
catch { }
}
#endregion
The number of columns, their properties and order can be specified automatically by creating a number of public properties derived from the class data:
#region Display columns
[showColumn(ReadOnly = true, Width = 100, Title = "Identification")]
public String DisplayIdent
{
get
{
return ident;
}
set
{
ident = value;
}
}
[showColumn(Width = 70, Title = "Number on Roll")]
public int DisplayNumber
{
get
{
return number;
}
set
{
number = value;
}
}
[showColumn(Width = -100, Title = "Name")]
public string DisplayName
{
get
{
return name == String.Empty ? "??" : name;
}
set
{
name = value;
}
}
#endregion
This would virtualize any class for dataGridView to display and edit data and I used it many times over the years and the extraction of properties to display is exactly what is required for XML serialization, indeed, it has a lot of the same characteristics.
I was going to adapt this method to do the same job for XML serialization but someone has already done it at https://www.codeproject.com/script/Articles/ViewDownloads.aspx?aid=474453, I hope you can make use of this method to solve your problem.
This works for me:
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Entity entity = new Entity();
entity.CausedBy = new List<Entity>();
entity.CausedBy.Add(new Subclass1());
entity.CausedBy.Add(new Subclass2());
entity.CausedBy.Add(new Subclass2());
entity.CausedBy.Add(new Subclass1());
entity.CausedBy.Add(new Subclass1());
entity.Save(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Test.txt"));
}
}
[Serializable]
[XmlRoot("Entity")]
public class Entity
{
[XmlArray("CausedBy")]
[XmlArrayItem("SubClass1", typeof(Subclass1))]
[XmlArrayItem("SubClass2", typeof(Subclass2))]
public List<Entity> CausedBy { get; set; }
}
[Serializable]
[XmlRoot("Subclass1")]
public class Subclass1 : Entity
{
[XmlIgnore]
String t = DateTime.Now.ToShortDateString();
public String SubClass1Item { get { return "Test1 " + t; } set { } }
}
[Serializable]
[XmlRoot("Subclass2")]
public class Subclass2 : Entity
{
[XmlIgnore]
String t = DateTime.Now.ToString();
public String SubClass2Item { get { return "Test2 " + t; } set { } }
}
It produces:
<Entity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CausedBy>
<SubClass1>
<SubClass1Item>Test1 20/09/2017</SubClass1Item>
</SubClass1>
<SubClass2>
<SubClass2Item>Test2 20/09/2017 01:06:55</SubClass2Item>
</SubClass2>
<SubClass2>
<SubClass2Item>Test2 20/09/2017 01:06:55</SubClass2Item>
</SubClass2>
<SubClass1>
<SubClass1Item>Test1 20/09/2017</SubClass1Item>
</SubClass1>
<SubClass1>
<SubClass1Item>Test1 20/09/2017</SubClass1Item>
</SubClass1>
</CausedBy>
</Entity>
I am sending 3 .net objects over the network:
- List<int>
- List<ParentObject>
- string
This is how I'm serializing (same for all types):
JsonSerializerSettings JSsettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Arrays
};
string message = JsonConvert.SerializeObject(listOfParents, JSsettings);
//listOfParents is of type List<ParentObject>
The ParentObject is an abstract class and has two child classes. It has a property to get which child type it represents.
public enum EntityType {Child1, Child2};
class ParentObject
{
public EntityType et { get; set; }
//..other members
}
I want to call 3 different functions based on which of the 3 objects is received.
Object genericObject = JsonConvert.DeserializeObject(message, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
if (genericObject is List<int>)
{
List<int> myList= (List<int>)genericObject;
myfunction1(myList);
}
if (genericObject is List<ParentObject>)
{
//etc..
The ParentObject is causing problems at DeserializeObject() because it says "Could not create an instance of type ParentObject. Type is an interface or abstract class and cannot be instantiated". So I was thinking I might need to use CustomCreationConverter at http://james.newtonking.com/projects/json/help/index.html?topic=html/CustomCreationConverter.htm
That still wouldn't solve my problem since the CustomCreationConverter needs the type during deserialization whereas I don't check the type until after deserialization.
Any suggestions to solve the problem?
If I use objects defined like this:
public enum EntityType { Child1, Child2 };
abstract class ParentObject
{
public EntityType et { get; set; }
}
class ChildClass : ParentObject
{
public int ChildClassProp { get; set; }
public ChildClass()
{
this.et = EntityType.Child1;
}
}
class ChildClass2 : ParentObject
{
public int ChildClass2Prop { get; set; }
public ChildClass2()
{
this.et = EntityType.Child2;
}
}
Then I can happily deserialize derived classes(ChildClass and ChildClass2) to ParentObject like this:
JsonSerializerSettings JSsettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
};
List<ParentObject> list = new List<ParentObject>();
list.Add(new ChildClass() { ChildClassProp = 1 });
list.Add(new ChildClass2() { ChildClass2Prop = 2 });
string message = JsonConvert.SerializeObject(list,
Newtonsoft.Json.Formatting.Indented, JSsettings);
list = JsonConvert.DeserializeObject<List<ParentObject>>(message, JSsettings);
Where message looks like this:
[
{
"$type": "ConsoleApplication4.ChildClass, ConsoleApplication4",
"ChildClassProp": 1,
"et": 0
},
{
"$type": "ConsoleApplication4.ChildClass2, ConsoleApplication4",
"ChildClass2Prop": 2,
"et": 1
}
]
The key in this one was using TypeNameHandling = TypeNameHandling.Auto for both serialization and deserialization. Using TypeNameHandling.Arrays creates a message that looks like this:
{
"$type": "System.Collections.Generic.List`1[[ConsoleApplication4.ParentObject, ConsoleApplication4]], mscorlib",
"$values": [
{
"ChildClassProp": 1,
"et": 0
},
{
"ChildClass2Prop": 2,
"et": 1
}
]
}
Note that the types of the list items are not included, only the type of the list, hence the error you were getting.
Edit:
I think the easiest way to get this working the way you want is to define a simple class like this one that acts as a thin wrapper around the object you are serializing:
class ObjectContainer
{
public object Data { get; set; }
}
Then the code would look like this (note the change to TypeNameHandling.Auto):
JsonSerializerSettings JSsettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
};
List<ParentObject> list = new List<ParentObject>();
list.Add(new ChildClass() { ChildClassProp = 1 });
list.Add(new ChildClass2() { ChildClass2Prop = 2 });
ObjectContainer container = new ObjectContainer()
{
Data = list
};
string message = JsonConvert.SerializeObject(container,
Newtonsoft.Json.Formatting.Indented, JSsettings);
var objectContainer = JsonConvert.DeserializeObject<ObjectContainer>(message, JSsettings);
if (objectContainer.Data is List<int>)
{
Console.Write("objectContainer.Data is List<int>");
}
else if (objectContainer.Data is List<ParentObject>)
{
Console.Write("objectContainer.Data is List<ParentObject>");
}
else if (objectContainer.Data is string)
{
Console.Write("objectContainer.Data is string");
}
The reason I have gone for this approach is that Json.Net will take care of almost all the work. Simply calling the non-generic JsonConvert.DeserializeObject method is fine, but you would then need to do additional work as this method returns a JContainer, not an object.
Well, my question is a bit silly, but I've tried lots of different thing without result.
I have a ComboBox in my main form and I want to point its data source to the public readonly List PriceChanges list declared in the Filters class. No problem with that but I want to list the Description field.
I tried to assign the "Description" string to the DisplayMember attribute without success. My ComboBox only lists: "BusinessLogic.PriceChange" for each entry, where BusinessLogic is the name of my Namespace and PriceChange the class.
I appreciate any help.
Regards
That's part of the code of my main form
public mainFrm()
{
InitializeComponent();
prodFilter = new Filters();
cbPriceChanges.DataSource = prodFilter.PriceChanges;
cbPriceChanges.DisplayMember = "Description"
}
That's is part of the code that declares the List object
public enum PriceChangeTypes
{
No_Change,
Increased,
Decreased,
All
}
public class PriceChange
{
public String Description;
public readonly PriceChangeTypes Type;
public delegate bool ComparisonFuntionDelegate(Decimal a);
public readonly ComparisonFuntionDelegate ComparisonFunction;
public PriceChange(String Description, PriceChangeTypes type , ComparisonFuntionDelegate CompFunc)
{
this.Description = Description;
Type = type;
ComparisonFunction = CompFunc;
}
}
public class Filters
{
public readonly List<PriceChange> PriceChanges = null;
public Filters()
{
PriceChanges = new List<PriceChange>();
PriceChanges.Add(new PriceChange("No Change", PriceChangeTypes.No_Change, PriceChange => PriceChange == 0));
PriceChanges.Add(new PriceChange("Increased", PriceChangeTypes.Increased, PriceChange => PriceChange > 0));
PriceChanges.Add(new PriceChange("Decreased", PriceChangeTypes.Decreased, PriceChange => PriceChange < 0));
PriceChanges.Add(new PriceChange("All", PriceChangeTypes.All, a => true));
}
}
Have you tried making "Description" a property? It will change a lot in case the list tries to get the field through reflection (as it most likely does).
public class PriceChange {
public string Description{
get;
set;
}
// ...
}
Try adding this to your class :
public override string ToString()
{
return Description;
}
Currently you're just getting the default value of ToString, which is the object namespace and class