How do I map enums in many-to-one relationship - c#

I have two enums, the source one is with responses from api and another one is what I want to send to frontend.
public enum ApiResponse
{
A=1,
B=2,
C=3,
D=4
}
public enum DestEnum
{
A=1,
BCD=2
}
What I am trying to do is:
public class ExampleViewModel
{
public DestEnum foo { get; set; }
}
var response = ApiResponse.C;
result = new ExampleViewModel()
{
foo = response
};
And I want foo value to be DestEnum.BCD
Is it possible to do with automapper or some custom attributes?

Assuming you've set your serializer up to send strings already you seem to be just looking for a way to map an X to a Y
How about:
public static class EnumExtensions{
static Dictionary<ApiResponse,DestEnum> _mapDest =
new() {
[ApiResponse.A] = DestEnum.A,
[ApiResponse.B] = DestEnum.BCD,
[ApiResponse.C] = DestEnum.BCD,
[ApiResponse.D] = DestEnum.BCD,
};
public static DestEnum AsDest(this ApiResponse x) => _mapDest[x];
}
And then you can convert the ApiRespnse you got to a Dest like:
return new BlahViewModel{
DestEnumProperty = apiResponseEnumValueIGot.AsDest(),
OtherProp = ...
}
Warning, the lookup will blow up if you get any values that aren't mapped; if you think this will ever be possible, consider having an Unknown value in your DestEnum and doing something like:
=> _mapDest.TryGetValue(x, out var r) ? r : DestEnum.Unknown

Related

How to implement property with parameter

I'm trying to implement a class with a property which can be accessed only with parameter. To clear my question see how I intend to use it
Note that this is different than Indexer. Please don't flag for duplicate.
My incomplete class
public class Inventory{
public object Options..... // I don't know how to define this property
}
How I'm going to use it
Inventory inv = new Inventory();
string invLabel = (string)inv.Options["Label"];
int size = inv.Options["Size"];
inv.Options["Weight"] = 24;
Internally, Options reads data from a private Dictionary. Please help me on how I can define the Options property.
Note: This is different than Indexer. With Indexer, I can use below code:
int size = inv["Size"];
But my usage is different.
I found a way to implement it.
public class Options
{
public Dictionary<string, object> _options;
public Options()
{
_options = new Dictionary<string, object>();
}
public object this[string key] {
get { return _options.Single(r => r.Key == key).Value; }
set { _options[key] = value; }
}
}
public class Inventory
{
public Inventory()
{
Options = new Options();
}
public Options Options { get; set; }
}
Usage:
var x = new Inventory();
x.Options["Size"] = 120;
x.Options["Box"] = "4 x 4 x 8";
Console.WriteLine(x.Options["Size"]);
Console.WriteLine(x.Options["Box"]);

How can I refer to a field of a class as some object, then use that object to obtain the field's value later?

Say I have the following code
public class FooClass
{
public int A { get; set; } = 0;
public int B { get; set; } = 0;
}
public class BarClass
{
public int X { get; set; } = 0;
public int Y { get; set; } = 0;
}
public class MyClass
{
int z = 0;
public FooClass Foo { get; set; } = new FooClass();
public BarClass Bar { get; set; } = new BarClass();
public static void MyMethod()
{
// List of MyClass objects
var myList = Enumerable.Range(1, 10).Select(_ => new MyClass()).ToList();
// Some flags set elsewhere
bool getFooAValues = true;
bool getBarYValues = true;
bool getClassZValues = true;
// Some statements that collects "field referecnes" of MyClass
var classFieldReferenceList = new List<...>();
if (getFooAValues)
classFieldReferenceList.Add(...);
if (getBarYValues)
classFieldReferenceList.Add(...);
if (getClassZValues)
classFieldReferenceList.Add(...);
// For each field reference
classFieldReferenceList.ForEach(classFieldRef =>
{
// For each class
myList.ForEach(myClassInst =>
{
// "Select"/"Apply" the reference to get the field value
var fieldValue = myClassInt.getTheFieldReferenceValue(classFieldRef);
// Do something with field value...
return fieldValue;
});
// Do something with the list of field values...
});
}
}
In this code, specifically in MyMethod, I create a list of MyClass objects. This class has a few fields, some are simply primitive types, some are instances of other classes. How can I refer to or address these fields in the form of some object I can pass around?
For example, I began writing code, akin to the following
public static void MyMethod()
{
// List of MyClass objects
var myList = Enumerable.Range(1, 10).Select(_ => new MyClass()).ToList();
// Some flags set elsewhere
bool getFooAValues = true;
bool getBarYValues = true;
bool getClassZValues = true;
if (getFooAValues)
{
var Avalues = myList.Select(myClassInst => myClassInst.Foo.A);
// Do Action X to list of values
}
if (getBarYValues)
{
var Yvalues = myList.Select(myClassInst => myClassInst.Bar.Y);
// Do Action X to list of values
}
if (getClassZValues)
{
var Zvalues = myList.Select(myClassInst => myClassInst.z);
// Do Action X to list of values
}
}
Where //Do Action X was quite a few lines of code that I would perform to each set of values (Plotting values on a plot, flags represent showing plot line or not). Though, I don't really want duplicate that code for each possible field I could refer/address within MyClass. Thus, I want to refer to a field by some "object" then "apply" that object to an instance of MyClass later to get the value of the field, if that makes sense.
I feel like this might be akin to defining a delegate? Though the delegate would be specific to some class structure?.. Or maybe there is some simple solution I have confused myself out of finding.
You can use Func<MyClass,object> delegate:
var classFieldReferenceList = new List<Func<MyClass,object>>();
if (...)
classFieldReferenceList.Add(m => m.Foo.A);
if (...)
classFieldReferenceList.Add(m => m.Foo.B);
if (...)
classFieldReferenceList.Add(m => m.Bar.X);
if (...)
classFieldReferenceList.Add(m => m.Bar.Y);
This is not ideal because object is used as the most common denominator, but that would be required for a "mixed bag" of types.
In your second example you could get away with a generic method:
private void DoActionsOnSelectedFields<T>(IEnumerable<MyClass> data, Func<MyClass,T> selector) {
foreach (T val in data.Select(selector)) {
... // Perform some common action
}
}

Work with interface but keep concrete values

I am trying to make a function that works with a list of an interface but I would like to keep the concrete class values for those lists. For example:
public interface GUID_OBJECT
{
string GUID { get; set; }
}
public class Car : GUID_OBJECT
{
public string GUID { get; set; }
public string CarSpecifikProp { get; set; }
}
public class Bike : GUID_OBJECT
{
public string GUID { get; set; }
public string BikeSpecifikProp { get; set; }
}
class Program
{
static void Main(string[] args)
{
var cars = new List<Car>() { new Car() { GUID = "1", CarSpecifikProp = "carstuff" }, new Car() { GUID = "2", CarSpecifikProp = "carsuff" } };
var bikes = new List<Bike>() { new Bike() { GUID = "1", BikeSpecifikProp = "bikestuff" }, new Bike() { GUID = "2", BikeSpecifikProp = "bikestuff" } };
var filteredCars = FilterGuidObjects(cars);
foreach (var car in filteredCars)
{
car.CarSpecifikProp = "changethis";
}
var filteredBikes = FilterGuidObjects(bikes);
foreach (var bike in filteredBikes)
{
bike.BikeSpecifikProp = "changethis";
}
Console.ReadKey();
}
static List<GUID_OBJECT> FilterGuidObjects(List<GUID_OBJECT> objects)
{
return objects.Where(x => x.GUID == "1").ToList();
}
}
This code doesn't work but it illustrates what I would like to do. I have a web api project that returns various type of lists of objects, but all these objects have some things in common such as GUID for example. Can I write functions that work with the interface GUID_OBJECT but keep the Car and Bike specific properties after that function returns its List of GUID_OBJECT interfaces? How would you deal with a scenario like this?
make a generic method with a constraint:
static List<G> FilterGuidObjects<G>(List<G> objects) where G: GUID_OBJECT
{
return objects.Where(x => x.GUID == "1").ToList();
}
The point of interfaces is to have only the common properties of the classes that implement them. If you need to use a specific property you'll need to cast to the type you want:
var obj = (MyType) myInterface
Since you're working with lists, you can cast the entire list like this:
listOfInterface.Cast<MyType>().ToList()
Consider implementing FilterGuidObjects as a generic function:
static List<T> FilterGuidObjects<T>(List<T> objects) where T : GUID_OBJECT
{
return objects.Where(x => x.GUID == "1").ToList();
}
there are many ways of achieving this but the crux of the matter is you have to convert the interface back to the original type
Method 1: generic filter on the function
static List<T> FilterGuidObjects(List<T> objects)
:where T:GUID_OBJECT
{
return objects.Where(x => x.GUID == "1").ToList();
}
Pros Quick and simple, will even infer the type automatically
Cons you can't feed in a Mixed list
Method 2 Type Filter the collection
var filteredCars = FilterGuidObjects(MixedListOfVechiles).OfType<Car>();
Pros Can handle mixed lists
Con have to specify the conversion every time
Method 3 Convert the Type Directly
var car = guid_object as Car
if(car != null)
car.CarSpecifikProp = "changethis";
or
if(guid_object is Car)
{
var car = (Car)guid_object
car.CarSpecifikProp = "changethis";
}
Pros doesn't use generics
Con requires lots of code

How can I convert data held as 01010 bits into fields in a class object?

I have two variables that contain true/false data. THe first variable can be null but the second variable is always non null. Both variables will always be the same length.
var AnswerGridCorrect = "000111"; // or null
var AnswerGridResponses = "000011";
How could I change this data into an object oriented form. I already created classes and these are below. Here's is what I need the output to look like when converted to JSON:
"answers":[ // Json conversion made Answers into answers
{"correct":null,"response":true},
{"correct":null,"response":true},
{"correct":null,"response":true},
{"correct":null,"response":false}
}
Note that I am using LINQ to output the data so I think what I need is a function with parameters something like this:
.Select((t, index) => new {
Answer = t.Answer,
Answers = makeAnswer(t.AnswerGridCorrect,
t.AnswerGridResponses)
});
I am not sure if this helps but here were the classes I was using when I did this from JSON:
public class AnswerRow
{
public bool? Correct { get; set; }
public bool Response { get; set; }
}
public class AnswerRowList
{
public IList<AnswerRow> AnswerRows { get; set; }
}
Here is an implementation for your makeAnswers method:
public List<AnswerRow> makeAnswers(string c, string r)
{
var result = new List<AnswerRow>();
for(var i=0; i<r.Length; i++)
{
result.Add(
new AnswerRow {
Correct = c!=null?new Nullable<bool>(c[i]=='1'):null,
Response = r[i]=='1'
});
}
return result;
}
Rene's answer is probably correct, but here's the (unnecessarily complex) Linq way:
AnswerRowList MakeAnswer(string answerGridCorrect, string answerGridResponses)
{
return new AnswerRowList()
{
AnswerRows = answerGridResponses.Zip(
answerGridCorrect == null ?
Enumerable.Repeat<bool?>(null, answerGridResponses.Length) :
answerGridCorrect.Select(x => new Nullable<bool>(x == '1')),
(r, c) => new AnswerRow()
{
Correct = c,
Response = r == '1'
}).ToList()
};
}

Select template

Is it possible to make a template for SELECT in a LINQ query? Right now I have 6 methods that uses the exact same SELECT, i would like to use a template if possible.
This is the code I'm using, when I want to make a change to the select I have to change the same thing at so many places in my code.
result = query.Select(b => new
{
route_id = b.b.route_id,
name = b.b.name,
description = b.b.description,
distance = b.b.distance,
distance_to_route = (int)b.distance_to_from_me,
departure_place = b.b.departure_place,
arrival_place = b.b.arrival_place,
owner = b.b.user.username,
average_rating = b.avg_rating,
is_favorite = b.is_favorite,
date = b.b.date,
attributes = b.b.route_attributes.Select(c =>
c.route_attribute_types.attribute_name),
coordinates = b.b.coordinates.Select(c =>
new coordinateToSend { sequence = c.sequence,
lat = c.position.Latitude,
lon = c.position.Longitude })
});
Here is a simple example of one way you could do this:
In your example, you're converting the source type to an anonymous type. You could create a class to represent your converted/result type, for example:
public class ResultClass
{
public string ResultPropA { get; set; }
}
For examples sake, lets say the following was the definition of your source class:
public class SourceClass
{
public string SourcePropA { get; set; }
}
Now that you have type definitions for your source and result objects, you can create an extension method to convert a collection of your source class to a collection of your result class:
public static class SourceToResultRepository
{
public static IEnumerable<ResultClass> ConvertSourceToResult
(this IEnumerable<SourceClass> source)
{
return source.Select(s => new ResultClass
{
ResultPropA = s.SourcePropA
//Add all other property transformations here
});
}
}
And here is an example of how you could use it wherever you need to perform the transformation:
//Extension usage:
var result = Database.Source.ConvertSourceToResult();
//Direct usage:
var result = SourceToResultRepository.ConvertSourceToResult(Database.Source);

Categories