I've built a complex filter for my ICollection within my ViewModel. Now I need a similar filterfunction for a different collection and datagrid. So I guess it would suck big times if I was going to duplicate and adjust my code.
So I was going for a reusable solution.
Simple Code:
public class FilterForGrid<T>
{
public T UiModel { get; set; }
private List<Predicate<T>> criteria = new List<Predicate<T>>();
public FilterForGrid() {
// var result = typeof(T).GetProperties().ToList();
}
private bool dynamicFilter(object obj) {
T uiModel = (T)obj;
bool isIn = true;
if (criteria.Count() == 0)
return isIn;
isIn = criteria.TrueForAll(x => x(uiModel));
return isIn;
}
public void ClearFilter() {
criteria.Clear();
}
public void AddFilterArgument(string argument, string property) {
// criteria.Add(new Predicate<T>(x => x.))
}
public void FireFilter(ICollectionView toBeFilteredCollection) {
toBeFilteredCollection.Filter = dynamicFilter;
toBeFilteredCollection.Refresh();
}
}
Have a look at the method "AddFilterArgument" --> I simply want to pass the name of the property and the value over which the data shall be filtered:
public void AddFilterArgument(string argument, string property) {
criteria.Add(new Predicate<T>(x => x.property == argument))
}
But because of type inteference the property can't be found this way.
Is my attemp possible or do I have to look in another direction? If its possible please give me a clue.
Well, finally it was a much easier than expected:
Example for one of the methods
public void AddFilterPredicate(string argument, string property, OperatorsForFIlter operators) {
Predicate<T> predicate;
if (!String.IsNullOrEmpty(argument)) {
switch (operators) {
case OperatorsForFIlter.equal:
predicate = new Predicate<T>(x => x.GetType().GetProperty(property).GetValue(x, null).ToString() == argument);
break;
case OperatorsForFIlter.contains:
predicate = new Predicate<T>(x => x.GetType().GetProperty(property).GetValue(x, null).ToString().Contains(argument));
break;
default:
predicate = null;
break;
}
} else { predicate = new Predicate<T>(x => x.GetType().GetProperty(property).GetValue(x, null).ToString().Contains(argument)); }
InsertIntoCriteriaCatalogue(property, predicate);
}
This line here was exactly what I was asking for:
new Predicate<T>(x => x.GetType().GetProperty(property).GetValue(x, null).ToString().Contains(argument));
I was looking for a way to pass a name of a property as parameter and the value of the property through which the list should be filtered.
Now I can use the dynamic generic filter for all my data in every grid.
The problem:
I have an html table with headers that include sort buttons. The data is fetched at the controller and sorted with OrderBy() based off a passed route value (a string). I'm currently using a gigantic switch statement that requires a col_asc and col_desc check for each column to determine the requested sort method. I want to whittle this down as much as possible and add a ThenBy sort that will also be passed as a route value.
Func<MProduct,int> orderByLambda;
switch (orderByColName)
{
case "asset_desc":
//models = models.OrderByDescending(m => m.AssetId);
orderByLambda = m => m.AssetId; // this is test code
break;
case "asset_asc":
models = models.OrderBy(m => m.AssetId);
break;
case "location_desc":
models = models.OrderByDescending(m => m.Locations.Name);
break;
case "location_asc":
models = models.OrderBy(m => m.Locations.Name);
break;
...... So on and so forth ......
case "manufacturer_desc":
models = models.OrderByDescending(m => m.Models.Manufacturers.Name);
break;
case "manufacturer_asc":
models = models.OrderBy(m => m.Models.Manufacturers.Name);
break;
default:
models = models.OrderByDescending(m => m.AssetId);
break;
}
The desired solution:
What I would like to do is break this apart and only check the actual column name in the switch statement and use a bool to check the asc/desc part. The switch statement would only assign the desired lambda expression to a variable (orderByLambda). The ordering function would look something like this:
private IEnumerable<MProduct> Order(
List<MProduct> items,
bool isDescending,
Func<MProduct, int> orderByLambda)
{
if (isDescending)
{
return items.OrderByDescending(orderByLambda);
}
return items.OrderBy(orderByLambda);
}
Where I'm stuck
This appears to work so far (Visual Studio isn't showing any red). However, since I have to declare the lambda variable as type Func<MProduct, int>, I can't pass the columns who's datatype is not an int. How can I overcome this? Is there a better way? I'm looking into the dynamic type but I'm not 100% sure that will work.
You could make Order generic, but that would mean that the caller would need to specify the type of the column.
private IEnumerable<MProduct> Order<T>(List<MProduct> items, bool isDescending, Func<MProduct, T> orderByLambda)
{
if (isDescending)
{
return items.OrderByDescending(orderByLambda);
}
return items.OrderBy(orderByLambda);
}
Another solution would be to not pass a func that is dependent on the column type. The Order method would take an Action with a parameter that has itself a generic method that will apply the appropriate order method:
private IEnumerable<MProduct> Order(List<MProduct> items, bool isDescending, Action<IApplyer<MProduct>> orderByLambda)
{
IApplyer<MProduct> applyer;
if (isDescending)
{
applyer = new OrderByApplyer<MProduct>(items);
}
else
{
applyer = new OrderDescendingByApplyer<MProduct>(items);
}
orderByLambda(applyer);
return applyer.Result;
}
// Usage
Order(items, true, a => a.Apply(o => o.Name));
Order(items, true, a => a.Apply(o => o.Age));
Dictionary<string, Action<IApplyer<MProduct>>> columns = new Dictionary<string, Action<IApplyer<MProduct>>>
{
["Name"] = a => a.Apply(o => o.Name),
["Age"] = a => a.Apply(o => o.Age),
};
Order(items, true, columns["Age"]);
//Implementation
interface IApplyer<TTarget>
{
void Apply<TColumn>(Func<TTarget, TColumn> orderBy);
IOrderedEnumerable<TTarget> Result { get; }
}
class OrderByApplyer<TTarget> : IApplyer<TTarget>
{
public OrderByApplyer(IEnumerable<TTarget> target)
{
this.Target = target;
}
public IEnumerable<TTarget> Target { get; }
public IOrderedEnumerable<TTarget> Result { get; set; }
public void Apply<TColumn>(Func<TTarget, TColumn> orderBy)
{
this.Result = this.Target.OrderBy(orderBy);
}
}
class OrderDescendingByApplyer<TTarget> : IApplyer<TTarget>
{
public OrderDescendingByApplyer(IEnumerable<TTarget> target)
{
this.Target = target;
}
public IEnumerable<TTarget> Target { get; }
public IOrderedEnumerable<TTarget> Result { get; set; }
public void Apply<TColumn>(Func<TTarget, TColumn> orderBy)
{
this.Result = this.Target.OrderByDescending(orderBy);
}
}
class ThenByApplyer<TTarget> : IApplyer<TTarget>
{
public ThenByApplyer(IOrderedEnumerable<TTarget> target)
{
this.Target = target;
}
public IOrderedEnumerable<TTarget> Target { get; }
public IOrderedEnumerable<TTarget> Result { get; set; }
public void Apply<TColumn>(Func<TTarget, TColumn> orderBy)
{
this.Result = this.Target.ThenBy(orderBy);
}
}
class ThenByDescendingByApplyer<TTarget> : IApplyer<TTarget>
{
public ThenByDescendingByApplyer(IOrderedEnumerable<TTarget> target)
{
this.Target = target;
}
public IOrderedEnumerable<TTarget> Target { get; }
public IOrderedEnumerable<TTarget> Result { get; set; }
public void Apply<TColumn>(Func<TTarget, TColumn> orderBy)
{
this.Result = this.Target.ThenByDescending(orderBy);
}
}
How do I make this expression dynamic based on the generic type passed in the parameter?
In the simplified form:
public static class CompareService
{
public static List<T> Run<T>(List<T> database_list, string directory_path)
{
var csv_list = CompareService.MergeRecordsFromFiles<T>(directory);
return CompareService.RunComparison<T>(database_list, csv_list);
}
public static T CompareData<T>(List<T> database_list, List<T> csv_list)
{
var diff = new List<T>();
foreach (var db_item in database_list)
{
// ...
// if T is of type Deathstar compare reference_number property
// if T is of type Stormtrooper compare id property
// if T is of type Sith compare id and anger_level property
var csv_item = csv_list.FirstOrDefault(x => x.reference_number == db_item.reference_number);
// Comparison code
ComparisonResult result = compareLogic.Compare(db_item, csv_item);
// ...
}
return diff;
}
}
It is called from another generic service:
public static void Whatever<T>(List<T> list)
{
// ...
var directory_path = "C:\";
var delta = CompareService.CompareData<T>(list, directory_path);
// ...
}
The most naive implementation would be to check if your itemToFind can be cast to DeathStar, StormTrooper or Sith and if so call the instances property.
var deathStar = itemToFind as DeathStar;
if(deathStar != null)
return database_list.Where(x => ((DeathStar)x).reference_number == deathStar.reference_number).FirstOrDefault();
else
{
var sith = itemToFind as Sith;
if(sith != null)
return database_list.Where(x => ((Sith)x).anger_level == sith.anger_level).FirstOrDefault();
else
return database_list.Where(x => ((StormTrooper)x).id== ((StormTrooper)item).id).FirstOrDefault();
}
This is quite cumbersome, including many casts. In particular it completely bypasses the actual benefits of generics using any arbitrary type (that fullfills the constraints if existing). In your case you´d have a generic method that will only wortk for three decent types.
A better approach is to let all your classes implement a common interface that defines a property, for instance:
interface IObject {
int Level { get; }
}
Now all classes define that level-property:
clas DeathStar : IObject
{
public int Level { get { return this.reference_number; } }
}
clas Sith : IObject
{
public int Level { get { return this.anger_level; } }
}
clas StormTrooper: IObject
{
public int Level { get { return this.id; } }
}
Than you can use a constraint on your type T to implement that interface:
public static T CompareData<T>(List<T> list, T itemToFind) where T: IObject
Why not like this:
public static T CompareData<T>(List<T> list, Func<T, bool> predicate)
{
return database_list.FirstOrDefault(predicate);
}
And then use it like this:
var itemToFind = new ItemToFind();
var myObjectList = new List<MyObject>();
var item = CompareData<MyObject>(myObjectList, x=> x.MyObjectProperty == itemToFind.Id);
You could add a property selector:
public static class CompareService
{
public static T CompareData<T>(this List<T> list, T itemToFind, Func<T, int> propSelector)
{
int propToFind = propSelector(itemToFind); // cache
return database_list.FirstOrDefault(x => propSelector(x) == propToFind);
}
}
And call it like that:
listOfDeathstars.CompareData(deathStarToFind, ds => ds.reference_number);
listOfStormtroopers.CompareData(trooperToFind, t => t.id);
listOfSiths.CompareData(sithStarToFind, sith => new { sith.id, sith.anger_level});
Note: I added the this keyword in the signature to make it an extension (not sure if you intended that but forgot the keyword). And Where(predicate).FirstOrDefault() can be reduced to FirstOrDefault(predicate).
Hi I'm wondering what the best approach would be to parse an OData $filter string in C#, for example
/API/organisations?$filter="name eq 'Facebook' or name eq 'Twitter' and subscribers gt '30'"
Should return all organisations with a name of Facebook or Twitter and who have more than 30 subscribers. I've researched quite a bit but can't find any solutions which don't revolve around WCF. I was thinking of using Regex and grouping them so I have a list
of Filter classes such that:
Filter
Resource: Name
Operator: Eq
Value: Facebook
Filter
Resource: Name
Operator: Eq
Value: Twitter
Filter
Resource: Subscribers
Operator: gt
Value: 30
but I'm stumped as how to handle ANDs / ORs.
In .NET, there's a library available that will do this for you. Writing your own regex runs the risk of missing some edge case.
Using NuGet, bring in Microsoft.Data.OData. Then, you can do:
using Microsoft.Data.OData.Query;
var result = ODataUriParser.ParseFilter(
"name eq 'Facebook' or name eq 'Twitter' and subscribers gt 30",
model,
type);
result here will be in the form of an AST representing the filter clause.
(To get the model and type inputs, you could parse your $metadata file using something like this:
using Microsoft.Data.Edm;
using Microsoft.Data.Edm.Csdl;
IEdmModel model = EdmxReader.Parse(new XmlTextReader(/*stream of your $metadata file*/));
IEdmEntityType type = model.FindType("organisation");
)
I think you are supposed to travserse the AST with the interface provided using the visitor pattern.
Consider you have this class that represents a filter
public class FilterValue
{
public string ComparisonOperator { get; set; }
public string Value { get; set; }
public string FieldName { get; set; }
public string LogicalOperator { get; set; }
}
So, how do we "extract" the filters that comes with the OData parameters to your class?
Well the FilterClause object have an Expression property which is a SingleValueNode wich inherits from a QueryNode. The QueryNode have the Accept method who takes a QueryNodeVisitor.
public virtual T Accept<T>(QueryNodeVisitor<T> visitor);
Right, so you must implement your own QueryNodeVisitor and do your stuff. Below is a non finished example (I dont override all possible visitors).
public class MyVisitor<TSource> : QueryNodeVisitor<TSource>
where TSource: class
{
List<FilterValue> filterValueList = new List<FilterValue>();
FilterValue current = new FilterValue();
public override TSource Visit(BinaryOperatorNode nodeIn)
{
if(nodeIn.OperatorKind == Microsoft.Data.OData.Query.BinaryOperatorKind.And
|| nodeIn.OperatorKind == Microsoft.Data.OData.Query.BinaryOperatorKind.Or)
{
current.LogicalOperator = nodeIn.OperatorKind.ToString();
}
else
{
current.ComparisonOperator = nodeIn.OperatorKind.ToString();
}
nodeIn.Right.Accept(this);
nodeIn.Left.Accept(this);
return null;
}
public override TSource Visit(SingleValuePropertyAccessNode nodeIn)
{
current.FieldName = nodeIn.Property.Name;
//We are finished, add current to collection.
filterValueList.Add(current);
//Reset current
current = new FilterValue();
return null;
}
public override TSource Visit(ConstantNode nodeIn)
{
current.Value = nodeIn.LiteralText;
return null;
}
}
Then, fire away :)
MyVisitor<object> visitor = new MyVisitor<object>();
options.Filter.FilterClause.Expression.Accept(visitor);
When it has traversed the tree your
visitor.filterValueList
should contain the filters in your desired format. Im sure more work is needed but if you can get this rolling I think you can figure it out.
Building on what Jen S says, you can traverse the AST tree that is returned by the FilterClause.
For instance, you can retrieve the FilterClause from the controller's query options:
public IQueryable<ModelObject> GetModelObjects(ODataQueryOptions<ModelObject> queryOptions)
{
var filterClause = queryOptions.Filter.FilterClause;
You can then traverse the resultant AST tree with code like the following (borrowed from this article):
var values = new Dictionary<string, object>();
TryNodeValue(queryOptions.Filter.FilterClause.Expression, values);
The function called is like so:
public void TryNodeValue(SingleValueNode node, IDictionary<string, object> values)
{
if (node is BinaryOperatorNode )
{
var bon = (BinaryOperatorNode)node;
var left = bon.Left;
var right = bon.Right;
if (left is ConvertNode)
{
var convLeft = ((ConvertNode)left).Source;
if (convLeft is SingleValuePropertyAccessNode && right is ConstantNode)
ProcessConvertNode((SingleValuePropertyAccessNode)convLeft, right, bon.OperatorKind, values);
else
TryNodeValue(((ConvertNode)left).Source, values);
}
if (left is BinaryOperatorNode)
{
TryNodeValue(left, values);
}
if (right is BinaryOperatorNode)
{
TryNodeValue(right, values);
}
if (right is ConvertNode)
{
TryNodeValue(((ConvertNode)right).Source, values);
}
if (left is SingleValuePropertyAccessNode && right is ConstantNode)
{
ProcessConvertNode((SingleValuePropertyAccessNode)left, right, bon.OperatorKind, values);
}
}
}
public void ProcessConvertNode(SingleValuePropertyAccessNode left, SingleValueNode right, BinaryOperatorKind opKind, IDictionary<string, object> values)
{
if (left is SingleValuePropertyAccessNode && right is ConstantNode)
{
var p = (SingleValuePropertyAccessNode)left;
if (opKind == BinaryOperatorKind.Equal)
{
var value = ((ConstantNode)right).Value;
values.Add(p.Property.Name, value);
}
}
}
You then can go through the list dictionary and retrieve your values:
if (values != null && values.Count() > 0)
{
// iterate through the filters and assign variables as required
foreach (var kvp in values)
{
switch (kvp.Key.ToUpper())
{
case "COL1":
col1 = kvp.Value.ToString();
break;
case "COL2":
col2 = kvp.Value.ToString();
break;
case "COL3":
col3 = Convert.ToInt32(kvp.Value);
break;
default: break;
}
}
}
This example is fairly simplistic in that it only accounts for "eq" evaluations, but for my purposes it worked well. YMMV. ;)
Thanks you #Stinky Buffalo for the answer.
i change your code and resolve error when add duplicate key in dictionary.
example:
CreateDate%20gt%202021-05-22T00:00:00Z%20and%20CreateDate%20lt%202021-05-26T00:00:00Z%20
and also:
BookRequestType%20eq%20%27BusDomestic%27%20or%20BookRequestType%20eq%20%27TrainDomestic%27%20or%20BookRequestType%20eq%20%27FlightDomestic%27%20
The following code worked very well for me:
first install Install-Package Microsoft.Data.OData -Version 5.8.4 package.
then create class with name 'ODataHelper' and after that copy below codes:
public class ODataHelper<T> where T : class
{
private static readonly TextInfo TextInfo = new CultureInfo("en-US", false).TextInfo;
public static Dictionary<string, Tuple<object, ODataOperatorType>> ODataUriParser(
ODataQueryOptions<T> queryOptions)
{
var dictFilters = new Dictionary<string, Tuple<object, ODataOperatorType>>();
TryNodeValue(queryOptions.Filter?.FilterClause?.Expression, dictFilters);
return dictFilters;
}
private static void TryNodeValue(SingleValueNode node,
IDictionary<string, Tuple<object, ODataOperatorType>> dictFilters)
{
if (node is null)
return;
if (node is SingleValueFunctionCallNode valueFunction)
{
ParseSingleFunctionNode(valueFunction,
Enum.Parse<ODataOperatorType>(TextInfo.ToTitleCase(valueFunction.Name)), dictFilters);
}
if (node is BinaryOperatorNode binaryOperatorNode)
{
var left = binaryOperatorNode.Left;
var right = binaryOperatorNode.Right;
if (left is SingleValuePropertyAccessNode leftNodeRight && right is ConstantNode rightNodeRight)
{
ParseSingleValueNode(
leftNodeRight,
rightNodeRight,
Enum.Parse<ODataOperatorType>(binaryOperatorNode.OperatorKind.ToString()),
dictFilters);
}
switch (left)
{
case ConvertNode node1:
{
var convertLeft = node1.Source;
if (convertLeft is SingleValuePropertyAccessNode leftNodeLeft &&
right is ConstantNode rightNodeLeft)
{
ParseSingleValueNode(
leftNodeLeft,
rightNodeLeft,
Enum.Parse<ODataOperatorType>(
binaryOperatorNode.OperatorKind.ToString()),
dictFilters);
}
else
TryNodeValue(node1.Source, dictFilters);
break;
}
case BinaryOperatorNode:
TryNodeValue(left, dictFilters);
break;
case SingleValueFunctionCallNode functionNode:
ParseSingleFunctionNode(functionNode,
Enum.Parse<ODataOperatorType>(TextInfo.ToTitleCase(functionNode.Name)),
dictFilters);
break;
}
switch (right)
{
case BinaryOperatorNode:
TryNodeValue(right, dictFilters);
break;
case ConvertNode convertNode:
TryNodeValue(convertNode.Source, dictFilters);
break;
case SingleValueFunctionCallNode functionNode:
ParseSingleFunctionNode(functionNode,
Enum.Parse<ODataOperatorType>(TextInfo.ToTitleCase(functionNode.Name)),
dictFilters);
break;
}
}
}
private static void ParseSingleValueNode(
SingleValuePropertyAccessNode left,
SingleValueNode right,
ODataOperatorType operatorKind,
IDictionary<string, Tuple<object, ODataOperatorType>> dictFilters)
{
string key = left.Property.Name.Trim();
object value = ((ConstantNode) right).Value;
object specifiedValue = value is ODataEnumValue enumValue ? enumValue.Value : value;
if (operatorKind is ODataOperatorType.LessThan or ODataOperatorType.LessThanOrEqual)
{
dictFilters.TryAdd($"{key}_To", new Tuple<object, ODataOperatorType>(value, operatorKind));
}
else if (dictFilters.TryGetValue(key, out Tuple<object, ODataOperatorType> currentValue))
{
dictFilters[key] = new Tuple<object, ODataOperatorType>(
$"{currentValue.Item1},{specifiedValue}",
operatorKind);
}
else
{
dictFilters.Add(key, new Tuple<object, ODataOperatorType>(specifiedValue, operatorKind));
}
}
private static void ParseSingleFunctionNode(
SingleValueFunctionCallNode node,
ODataOperatorType operatorKind,
IDictionary<string, Tuple<object, ODataOperatorType>> dictFilters)
{
string key = (node.Parameters.First() as SingleValuePropertyAccessNode)?.Property.Name.Trim();
object value = (node.Parameters.Last() as ConstantNode)?.Value;
if (string.IsNullOrEmpty(Convert.ToString(value)?.Trim()))
return;
dictFilters.TryAdd(key, new Tuple<object, ODataOperatorType>(value, operatorKind));
}
}
public enum ODataOperatorType
{
Equal,
NotEqual,
GreaterThan,
GreaterThanOrEqual,
LessThan,
LessThanOrEqual,
Contains
}
for call ODataUriParser method you need to get the value from the input action.
get ODataQueryOptions<YourObjectModel> from request api :
input endpoint action => ODataQueryOptions<YourObjectModel> options
public Task<IQueryable<YourObject>> Get(ODataQueryOptions<YourObject> options)
{
// call your service class
}
then write below codes in your service class for call ODataUriParser and use the result runction:
Dictionary<string, Tuple<object, ODataOperatorType>> dictFilters =
ODataHelper<YourObject>.ODataUriParser(options);
An example of how to use ODataUriParser method result:
if (dictFilters.TryGetValue("Email", out Tuple<object, ODataOperatorType> emailValue))
{
bookRequestProfileDto.Email =
Convert.ToDateTime(emailValue.Item1.ToString());
}
For example, we want to convert a list of numeric strings to a list of text strings using the Enum:
BookRequestType is enumuration class.
if (dictFilters.TryGetValue("BookRequestType", out Tuple<object, ODataOperatorType> bookRequestTypeValue))
{
customerTransactionDto.BookRequestType =
Convert.ToString(bookRequestTypeValue.Item1)
.ConvertStringNamesEnumToStringNumbers<BookRequestType>();
}
// Extesion Method
public static string ConvertStringNamesEnumToStringNumbers<T>(this string stringTypes) where T : Enum
{
var separateStringTypes = stringTypes.Split(',');
StringBuilder stringBuilder = new StringBuilder();
foreach (var item in separateStringTypes)
{
stringBuilder.Append((int) Enum.Parse(typeof(T), item)).Append(',');
}
return stringBuilder.ToString().Remove(stringBuilder.Length - 1);
}
For a project i've created several struct in C#.
The probject itself is a ASP.Net MVC 2 project.
snip:
struct TDummy
{
private char _value;
public TDummy(char value)
{
this._value = value; // Restrictions
}
}
I created this because I needed to restrict a char-variable to a specific number of values. (I could have created an Enum, but these values are also used in the database, and then i would still need to convert them)
Now i need to create a JsonResult, like
return Json(new { Value = new TDummy('X') });
But when I do this, I get a result of:
{"Value":{}}
I expected to get a result of
{"Value":"X"}
I've tried several things, like TypeConverter (CanConvertTo(string)), Custom Type Serializer (JavaScriptSerializer.RegisterConverters()), but either they don't work or they must return a 'Complex' json-object.
{"Value":{"Name":"Value"}}
Any thoughts on this?
I want to serialize a value-type as a value...
If anyone is interested, i've create a small demo (console app) to illustrate this:
public struct TState
{
public static TState Active = new TState('A');
public static TState Pending = new TState('P');
private char _value;
public TState(char value)
{
switch (value)
{
case 'A':
case 'P':
this._value = value; // Known values
break;
default:
this._value = 'A'; // Default value
break;
}
}
public static implicit operator TState(char value)
{
switch (value)
{
case 'A':
return TState.Active;
case 'P':
return TState.Pending;
}
throw new InvalidCastException();
}
public static implicit operator char(TState value)
{
return value._value;
}
public override string ToString()
{
return this._value.ToString();
}
}
public class Test { public TState Value { get; set; } }
class Program
{
static void Main(string[] args)
{
Test o = new Test();
o.Value = 'P'; // From Char
char c = o.Value; // To Char
Console.WriteLine(o.Value); // Writes 'P'
Console.WriteLine(c); // Writes 'P'
JavaScriptSerializer jser = new JavaScriptSerializer();
Console.WriteLine(jser.Serialize(o)); // Writes '{"Value":{}}'
Console.ReadLine();
}
}