Can't Deserialize generic class with specific implicit method - c#

I have an old type of data and what to convert it to another generic one using implicit method
it's works if you use types like long or string but with specific classes not...
void Main()
{
var js = "{\"Content\":{\"B\": \"1\", \"C\": 1}}";
var result = JsonConvert.DeserializeObject<A>(js);
Console.WriteLine(result);
}
public class A{
public MLString<AB> Content {get; set;}
}
public class AB{
public string B {get; set;}
public int C {get; set;}
}
public class MLString<T>
{
public T DefaultValue;
public Dictionary<string, T> Translates = new Dictionary<string, T>();
public static implicit operator MLString<T>(T val)
{
return new MLString<T>() {DefaultValue = val};
}
public static implicit operator MLString<T>(Dictionary<string, T> val)
{
return new MLString<T>() {Translates = val};
}
}
How can I desirialize it?

Related

Using generic types within a foreach loop

I really cannot figure out how to use generic types with IEnumerable so that I can iterate through values contained by a given generic value.
Consider the following class (note that the classes here are only for example purposes):
public class Parameter<T> : IParameter<T> where T : IEnumerable<T>
{
public List<UInt64> output = new List<UInt64>();
private T _value;
public T Value
{
get => ...;
set
{
// I want to be able to apply special treat to the value
// Value can be of any type: int, int[], bool, bool[]
foreach (var v in value)
{
output.Add(Convert.UInt64(v) + 5);
}
...
}
}
}
public interface IParameter<T> where T : IEnumerable<T>
{
T Value { get; set; }
}
I then have a test module that instantiate some parameters as per, but I cannot even compile here. I have even tried to replace bool[] to IEnumerable here below, but the compiler does not like it either.
public class TestModule : ModuleBase, ITestModule
{
public IParameter<bool[]> Test1 { get; set; } = new Parameter<bool[]>();
public IParameter<uint[]> Test2 { get; set; } = new Parameter<uint[]>();
...
public IParameter<int> Test3 { get; set; } = new Parameter<int>();
}
I did consider using overload for the Parameter() class, but I thought it to be overkill to create a class per supported type (considering it is only for the Value property).
Your issue is that your generic parameter is specified incorrectly.
public class Parameter<T> : IParameter<T> where T : IEnumerable<T>
implies that whatever comes in of type T is an enumerable of the same type, meaning for instance a T of type bool[] should be an IEnumerable<bool[]> which is clearly incorrect.
One way to get it to compile is this:
public class Parameter<TEnumerable, TType> : IParameter<TEnumerable, TType> where TEnumerable : IEnumerable<TType>
{
public List<ulong> output = new List<ulong>();
private TEnumerable _value;
public TEnumerable Value
{
get => { return null; }
set
{
// I want to be able to apply special treat to the value
// Value can be of any type: int, int[], bool, bool[]
foreach (Q v in value)
{
output.Add(Convert.ToUInt64(v) + 5);
}
}
}
}
public interface IParameter<TEnumerable, TType> where TEnumerable : IEnumerable<TType>
{
TEnumerable Value { get; set; }
}
public class TestModule
{
public IParameter<bool[], bool> Test1 { get; set; } = new Parameter<bool[], bool>();
public IParameter<uint[], uint> Test2 { get; set; } = new Parameter<uint[], uint>();
public IParameter<int[], int> Test3 { get; set; } = new Parameter<int[], int>();
}
As for your additional comment, no, there's no way you can avoid having to specify the two types since IEnumerable is not a T in the form you've formulated your code. You have 2 separate parameters here and as such, you will have to use 2 generic parameters if you must do it the way you've done it.
A much simpler solution to your problem would be something like this which serves the same purpose more or less, although I don't really know your requirements so this may or may not suffice (interface omitted for clarity):
public class Parameter<TType>
{
public List<ulong> output = new List<ulong>();
private IEnumerable<TType> _value;
public IEnumerable<TType> Value
{
get => { return null; }
set
{
// I want to be able to apply special treat to the value
// Value can be of any type: int, int[], bool, bool[]
foreach (TType v in value)
{
output.Add(Convert.ToUInt64(v) + 5);
}
}
}
}
public class TestModule
{
public Parameter<bool> Test1 { get; set; } = new Parameter<bool>();
public Parameter<uint> Test2 { get; set; } = new Parameter<uint>();
public Parameter<int> Test3 { get; set; } = new Parameter<int>();
}

How do I implement extension helper methods as an abstract class with variable parameters?

To cut down on reused code throughout my repository which gets values from another library, I wanted to create extension methods for "parsing"(for lack of a better word) one class to another. How do I implement abstract methods with different parameters.
I can't find anything that answers my question, and I'm not sure it can even be done.
Instead of having something like this in multiple places.
var list = _library.GetList();
var model = list.Select(o => new ClassA()
{
ID = o.ID,
Name = o.Name
}).ToList<ClassA>();
I want extension methods so I can call something like
var list = _library.GetList();
var model = ExtensionClass.ParseMany(list);
But, I want to base this off an abstract class so it can be reused by mutliple different classes, so I have
public abstract class Parser<U, T> where T : class where U : class
{
public abstract T ParseOne(U parser);
public abstract IEnumerable<T> ParseMany(IEnumerable<U> parser);
}
public class ParseA<ClassA, ClassADTO>
{
public override ClassA ParseOne(ClassADTO parser){ // }
}
But it doesn't seem that my parameter that is passed in is the actual object, it says it's a KeyValuePair and now I'm lost.
I expect to able to return a new instance based on my parameter, basically what I already do in my code multiple times.
I guess you can have a generic parser using Func. I just wrote a sample and hope it helps you.
public class ClassA
{
public int SomeNumber { get; set; }
public string SomeString { get; set; }
}
public class ClassB
{
public int OtherNumber { get; set; }
public string OtherString { get; set; }
}
public static class ExecuteParsingFunction
{
public static TDestiny Parse<TOrigin, TDestiny>(TOrigin origin,
Func<TOrigin, TDestiny> parserFunction)
{
return parserFunction(origin);
}
}
public static class ParsingFunctions
{
public static ClassB ParseAToB(ClassA a)
{
return new ClassB { OtherNumber = a.SomeNumber, OtherString = a.SomeString };
}
public static IEnumerable<ClassB> ParseManyAToB(IEnumerable<ClassA> aCollection)
{
foreach(var a in aCollection)
yield return ParseAToB(a);
}
}
public void Sample()
{
var a = new ClassA { SomeNumber = 1, SomeString = "Test" };
var manyAs = new List<ClassA> { a };
var b = ExecuteParsingFunction.Parse(a, ParserFunctions.ParseAToB);
var manyBs = ExecuteParsingFunction.Parse(manyAs, ParserFunctions.ParseManyAToB);
}

How can one create a variable to hold class instance with <TSource> using c#?

I have a class that requires an object to be passed in order to create a new instance of it like. My class looks like so
public class TableMapper<TSource>
{
........
}
When I make a new instance of it I do the following.
private readonly TableMapper<Client> Mapper; // Client is an instance of a EF model.
Now, I want to create an instance of it as a variable in a new class. So my new class will look something like the following
// The syntax below is incorrect!!
public class IReportRelation
{
TableMapper<TSource> localMapper { get; set; } //incorrect usage
Func<string, string> localProperty { get; set;}
Func<string, string> foreignProperty { get; set; }
TableMapper<TSource> foreignMapper { get; set; } //incorrect usage
}
Yet from another class named TableMapper, I need a method that will create an instance of IReportRelation class from within a method like so
public IReportRelation Relation<TProperty>(Expression<Func<TSource, TProperty>> lProperty, TableMapper<TSource> fMapper, Expression<Func<TSource, TProperty>> fKey)
{
return new IReportRelation { localProperty = lProperty; foreignMapper = fMapper; foreignProperty = fKey};
}
I am hoping I can call my Relation method with something like so
public override List<IReportRelation> ReportRelations
{
get
{
new List<IReportRelation>
{
Mapper.Relation(x => x.ClientId, TableMapper<Client>, c => c.Id),
};
}
}
How can I correctly create that have a property that holds an instance of another class where will be what every I pass to it?
Change your IReportRelation -interface to the following:
public class IReportRelation<TLocal, TForeign>
{
public TableMapper<TLocal> localMapper { get; set; }
public Func<string, string> localProperty { get; set; }
public Func<string, string> foreignProperty { get; set; }
public TableMapper<TForeign> foreignMapper { get; set; }
}
With two different generic parameters, you can differ between source and target
EDIT:
public IReportRelation<T1, T2> Relation<T1, T2>(TableMapper<T1> lMapper, Func<string, string> lProperty, TableMapper<T2> fMapper, Func<string, string> fKey)
{
return new IReportRelation<T1, T2> { localMapper = lMapper, localProperty = lProperty, foreignMapper = fMapper, foreignProperty = fKey };
}
I highly recommend you also, not to prefix a class with I. IReportRelation indicates, its an Interface
Usage:
public void SomeMethod(){
var xx = this.Relation(new TableMapper<Student>(), dummy, new TableMapper<Department>(), dummy);
}
string dummy(string xx)
{
return xx + "Hello";
}

typesafe enum and implicit operator

I created a Unit class that implements the typesafe enum pattern. I implemented an implicit operator in it to simplify its usage. But I want to refactor the implicit operator from string to Unit. Currently, I'm using a switch block but this will get huge pretty quick once I add more units. My current code looks like this.
[DataContract]
public class Unit
{
public static readonly Unit USFeet = new Unit("US Feet", 1);
public static readonly Unit Meters = new Unit("Meters", 0.3048006096);
[DataMember] public double ConversionConstant { get; private set; }
[DataMember] private string Name { get; set; }
private Unit(string name, double conversionConstant)
{
Name = name;
ConversionConstant = conversionConstant;
}
public override string ToString()
{
return Name;
}
public static implicit operator string(Unit unit)
{
return unit.Name;
}
public static implicit operator Unit(string name)
{
switch (name)
{
case "US Feet":
return USFeet;
case "Meters":
return Meters;
default:
return null;
}
}
}
So my question is, is there a better way to approach this instead of using a switch block?
I tried something like this but it doesn't work...
public static SortedList<string, Unit> UnitList = new SortedList<string, Unit>();
private Unit(string name, double conversionConstant)
{
Name = name;
ConversionConstant = conversionConstant;
UnitList.Add(name, this);
}
public static implicit operator Unit(string name)
{
return UnitList[name];
}
You can build a lookup table, and update it from the .ctor :
private static Dictionary<string, Unit> definedUnits = new Dictionary<string, UserQuery.Unit>();
private Unit(string name, double conversionConstant)
{
Name = name;
ConversionConstant = conversionConstant;
definedUnits.Add(name, this);
}
public static implicit operator Unit(string name)
{
Unit result;
return definedUnits.TryGetValue(name, out result) ? result : null;
}
You can also build that table dynamically with reflection :
private static Dictionary<string, Unit> definedUnits = typeof(Unit)
.GetFields(BindingFlags.Public | BindingFlags.Static)
.Where(x => x.IsInitOnly && x.FieldType == typeof(Unit))
.ToDictionary(x => x.Name, x => (Unit)x.GetValue(null));
It seems that what I tried above will work when done like this (I believe it's called lazy initialization)
[DataContract]
public class Unit
{
public static readonly Unit USFeet = new Unit("US Feet", 1);
public static readonly Unit Meters = new Unit("Meters", 0.3048006096);
private static Dictionary<string, Unit> _unitList;
public static readonly Dictionary<string, Unit> UnitList = _unitList ?? (_unitList = new Dictionary<string, Unit>());
[DataMember] private readonly double _conversionConstant;
[DataMember] private readonly string _name;
private Unit(string name, double conversionConstant)
{
_name = name;
_conversionConstant = conversionConstant;
UnitList.Add(name, this);
}
}

Generic type constraint and variance

I am building a simple type mapper similar to AutoMapper but with a more dynamic behaviour. The caller can decide to filter RecordStatus == RecordStatus.Deleted records when mapping from entity framework models.
Abstract mappers:
public interface IMapper<in TIn, out TOut>
{
TOut Map(TIn input);
}
public interface IRecordStatusFilterable
{
string RecordStatus { get; }
}
public abstract class RecordStatusFilterableMapperBase<TIn, TOut> : IMapper<TIn, TOut>
{
private readonly bool _filterDeletedRecords;
protected RecordStatusFilterableMapperBase(bool filterDeletedRecords)
{
_filterDeletedRecords = filterDeletedRecords;
}
protected bool FilterDeletedRecords
{
get { return _filterDeletedRecords; }
}
public abstract TOut Map(TIn input);
}
public class MultiLookupValuesMapper : RecordStatusFilterableMapperBase<IEnumerable<Lookup>, string>
{
private static readonly Func<Lookup, bool> _predicate =
filterable => filterable.RecordStatus == RecordStatus.Active;
protected MultiLookupValuesMapper(bool filterDeletedRecords) : base(filterDeletedRecords)
{
}
public override string Map(IEnumerable<Lookup> input)
{
var inputList = input as IList<Lookup> ?? input.ToList();
if (!inputList.Any())
{
return string.Empty;
}
if (FilterDeletedRecords)
{
inputList = (IList<Lookup>)inputList.Where(_predicate);
}
return string.Join(", ", inputList.Select(l => l.Value));
}
}
Concrete Mappers:
public class FooMapper<TRecordStatusFilterable> : RecordStatusFilterableMapperBase<Foo, FooViewModel>
where TRecordStatusFilterable : class, IRecordStatusFilterable
{
private readonly IMapper<IEnumerable<TRecordStatusFilterable>, string> _multiLookupValueMapper;
public FooMapper(IMapper<IEnumerable<TRecordStatusFilterable>, string> multiLookupValueMapper,
bool filterDeletedRecords) : base(filterDeletedRecords)
{
_multiLookupValueMapper = multiLookupValueMapper;
}
public override FooViewModel Map(Foo input)
{
return new FooViewModel
{
// Error here
BarLookupValues = _multiLookupValueMapper.Map(input.Lookups)
};
}
}
Entity Framework model:
public class Foo
{
public ICollection<Lookup> Lookups { get; set; }
}
public class Lookup : IRecordStatusFilterable
{
public string Value { get; set; }
public string RecordStatus { get; set; }
}
ViewModels:
public class FooViewModel
{
// ICollection<Lookup> => string
public string BarLookupValues { get; set; }
}
I got a compile error:
Argument 1: cannot convert from 'System.Collections.Generic.IEnumerable<Lookup>' to 'System.Collections.Generic.IEnumerable<TRecordStatusFilterable>'
But my Lookup class does fulfill the generic type parameter constraint as it implements IRecordStatusFilterable. Can anyone shed some light on this?
Actually a lot of the code is irrelevant to the actual problem. Here is a simpler version that, hopefully, illustrates it better:
class MyList<T>
where T : class, IConvertible
{
private List<T> list = new List<T>();
public void Add(string s)
{
list.Add(s); // error
}
}
Yes T is constrained, and string fits the constraints, but that doesn't mean you can go and add string to a List of arbitrary T's. That wouldn't type safe.
If I defined
class Bar : IConvertible { /* left out IConvertible impl */ }
and made a var bars = new MyList<Bar>() it is obvious that adding a string to bars is a problem for that code in the generic class.
You've just got a more complex version of this and I'm not 100% sure what exactly you are trying to express. Perhaps the class FooMapper shouldn't be generic at all and should just take an instance of IMapper<IEnumerable<Lookup>, string>.

Categories