Use reflection to get a dictionary from subclasses - c#

If I have a class of classes of static strings, like this:
public class Urls {
public static class App1 {
public static string URL1 = "http://....1";
public static string URL2 = "http://....2";
}
public static class App2 {
public static string URL3 = "http://....3";
public static string URL4 = "http://....4";
}
private static Dictionary<string, string> _dict;
private static Dictionary<string, string> URLDictionary {
get {
if(_dict != null) return _dict;
return _dict = [WHAT GOES HERE?];
}
}
}
I need to use reflection cause I dont want to have to manage a dictionary, I just want to get the fields out of the classes.
What do I put in [WHAT GOES HERE?] in order to made URLDictionary equal to this:
Dictionary<string, string>(){
{"Url1", "http://.....1"},
{"Url2", "http://.....2"},
{"Url3", "http://.....3"},
{"Url4", "http://.....4"}
};
?
Or, even better, this:
Dictionary<string, Dictionary<string, string>>(){
{"App1", new Dictionary<string, string>() {
{"Url1", "http://.....1"},
{"Url2", "http://.....2"},
},
{"App2", new Dictionary<string, string>() {
{"Url3", "http://.....3"},
{"Url4", "http://.....4"},
},
};

There might be a more elegant answer, but this works.
public static Dictionary<string, Dictionary<string, string>> URLs
{
get
{
if (_URLs != null)
return _URLs;
_URLs =
typeof(HealthURLs).GetNestedTypes(BindingFlags.Static | BindingFlags.Public)
.Select(m => new KeyValuePair<string, Dictionary<string, string>>(
m.Name,
m.GetFields()
.Select(k => new KeyValuePair<string, string>(
k.Name,
k.GetValue(null).ToString()))
.ToDictionary(x => x.Key, x => x.Value)))
.ToDictionary(x => x.Key, x => x.Value);
return _URLs;
}
}

_dict = typeof(Urls).GetNestedTypes().ToDictionary(t => t.Name, t => t.GetFields(BindingFlags.Static | BindingFlags.Public).ToDictionary(p => p.Name, p => p.GetValue(null)));

Related

Easier way of seperating dictionary items by value types

I have a script that contains these functions:
public Dictionary<string, float> GetFloatVariables(){
Dictionary<string, float> floatDict = new Dictionary<string, float>();
foreach (var variable in variables)
{
var type = variableTypes[variable.Key];
if (type == typeof(float))
{
float value = System.Convert.ToSingle(variable.Value);
floatDict.Add(variable.Key, value);
}
}
return floatDict;
}
public Dictionary<string, bool> GetBoolVariables(){
Dictionary<string, bool> boolDict = new Dictionary<string, bool>();
foreach (var variable in variables)
{
var type = variableTypes[variable.Key];
if (type == typeof(bool))
{
bool value = System.Convert.ToBoolean(variable.Value);
boolDict.Add(variable.Key, value);
}
}
return boolDict;
}
public Dictionary<string, string> GetStringVariables(){
Dictionary<string, string> stringDict = new Dictionary<string, string>();
foreach (var variable in variables)
{
var type = variableTypes[variable.Key];
if (type == typeof(string))
{
string value = System.Convert.ToString(variable.Value);
stringDict.Add(variable.Key, value);
}
}
return stringDict;
}
While this way of doing things is working, I feel like its kind of redundant to loop through "variables" dictionary every time I want to call all 3 methods.
May I know if there is a better way of doing this? Perhaps using LINQ
You can use generics <T> to have one method instead of three and Linq to get rid of loops:
using System.Linq;
...
public Dictionary<string, T> GetVariables<T>() => variables
.Where(pair => pair.Value is T)
.ToDictionary(pair => pair.Key, pair => (T) (pair.Value));
Usage:
var boolDictionary = GetVariables<bool>();
var floatDictionary = GetVariables<float>();
var stringDictionary = GetVariables<string>();

How would I deserialize a json dictionary to its original object type?

I wrote the following function:
public static Dictionary<string, string> GetObjectPropertiesAsDic<T>(T obj) where T : class
{
return JObject.FromObject(obj).Properties().ToDictionary(k => k.Name, v => v.Value?.ToString());
}
Which is a one liner to help me converting a type to a dictionary of its properties.
I can't come up with a way (one, two, three... liners ? :) to do the reverse.
Anyone?
Add a trick with value serializing:
public static Dictionary<string, string> GetObjectPropertiesAsDict<T>(T obj) where T : class
{
return JObject
.FromObject(obj)
.Properties()
.ToDictionary(
k => k.Name,
v => v.Value == null ?
null :
JsonConvert.SerializeObject(v.Value)
);
}
public static T FromDictionary<T>(Dictionary<string, string> dict) where T: new()
{
T res = new T();
foreach (var prop in typeof(T).GetProperties())
{
if (dict.ContainsKey(prop.Name))
{
prop.SetValue(res,JsonConvert.DeserializeObject(dict[prop.Name],prop.PropertyType));
}
}
return res;
}
Here is example https://dotnetfiddle.net/AMI2Dp

Create lambda expression for OrderBy based on string

The method MyMethod as a string parameter. Based on the value of this parameter, I'd like get back an expression to use with an OrderBy. I don't find the right syntax for Expression<Func<>> to use with the dictionary (as TValue type)
public void MyMethod(string orderBy)
{
var dico = new Dictionary<string, string>
{
{ "property1", x => x.Name},
{ "property2", x => x.Age},
};
dico.TryGetValue("property1", out string myOrder);
myList.OrderBy(myOrder)......
}
Update :
var dico = new Dictionary<string, Expression<Func<Person, xxxxx>>>
{
{ "property1", x => x.Name},
{ "property2", x => x.Age},
};
Thanks,
I think you may get hints from this:
public void MyMethod(string orderBy)
{
// Assuming Product has 'Name' and 'Age' property ?
var dico = new Dictionary<string, Expression<Func<Product,object>>>
{
{ "property1", x => x.Name},
{ "property2", x => x.Age},
};
Expression<Func<Product,object>> myorder;
dico.TryGetValue(orderBy, out myOrder);
_context.Products.OrderBy(myOrder);
}

How to name dictionary/list with variable

I get fed JSON data and I need to create a varying amount of dictionaries to store events in. I can't seem to figure out or find and answer to something like this:
Creating a Dictionary:
foreach (Identity x in List.Identities)
{
Dictionary<int, int> shop + x.Id = new Dictionary<int, int>();
Dictionary<int, int> de + x.Id = new Dictionary<int, int>();
Dictionary<int, int> sell + x.Id = new Dictionary<int, int>();
}
So that later I can also input the varying number of events with max efficiency:
foreach (Event x in y.events)
{
if ((x.Type.Contains("PURCHASED")){
shop+x.Id.Add(x.timestamp, x.item);
}
if ((x.Type.Contains("SOLD")){
sell+x.Id.Add(x.timestamp, x.item);
}
if ((x.Type.Contains("DESTROYED")){
de+x.Id.Add(x.timestamp, x.item);
}
}
I know this is definitely NOT the way to declare these, but I can't find a way to have an int variable declared in the dictionary name. If this works with lists, that would work as well, anything that I can foreach. Thanks!
Here's the classes to avoid confusion:
public class Event
{
public string Type { get; set; }
public int timestamp { get; set; }
public int item { get; set; }
public int Id { get; set; }
}
public class ParticipantIdentity
{
public int Id { get; set; }
}
You don't. Variable names in C# are never dynamic - it sounds like you want a map from ID to "dictionary of timestamp to item".
In fact, I would probably create a separate type of ItemEvents or something similar, which contained all the events for items with a single ID - e.g. by having three dictionaries within it.
You'd then just need:
var eventsByItem = List.Identities.GroupBy(x => x.Id)
.Select(g => new ItemEvents(g.Key, g))
.
where the ItemEvents constructor would do the splitting, e.g.
public ItemEvents(int id, IEnumerable<Event> events)
{
this.id = id;
shops = events.Where(e => e.Type.Contains("PURCHASED"))
.ToDictionary(e => e.timestamp, e => e.item);
// Ditto for the other dictionaries.
}
As an aside, I would try to use a more meaningful type than int for a timestamp - and consider using an enum for the event type.
You can create yet another set of dictionaries, with x.Id being a key:
Dictionary<int, Dictionary<int, int>> shops = Dictionary<int, Dictionary<int, int>>;
Dictionary<int, Dictionary<int, int>> des = Dictionary<int, Dictionary<int, int>>;
Dictionary<int, Dictionary<int, int>> sells = Dictionary<int, Dictionary<int, int>>;
So later you can do this:
foreach (Identity x in List.Identities)
{
shops[x.Id] = new Dictionary<int, int>();
...
}
and this:
if ((x.Type.Contains("PURCHASED")){
shops[x.Id].Add(x.timestamp, x.item);
}
What you are looking for is a dirctionary of dictionaries:
var shops = new Dictionary<int,Dictionary<int, int>>();
foreach (Identity x in List.Identities)
{
shops.Add(x.Id,new Dictionary<int, int>());
//des and shells the same way
}
and then
foreach (Event x in y.events)
{
if ((x.Type.Contains("PURCHASED")){
shops[x.Id].Add(x.timestamp, x.item);
}
As you know, you can't dynamically create variable names like that.
You could create a dictionary of dictionaries:
var dictionaries = new Dictionary<string, Dictionary<int, int>>();
foreach (Identity x in List.Identities)
{
dictionaries.add("shop" + x.Id, new Dictionary<int, int>());
dictionaries.add("de" + x.Id, new Dictionary<int, int>());
dictionaries.add("sell" + x.Id, new Dictionary<int, int>());
}
foreach (Event x in y.events)
{
if ((x.Type.Contains("PURCHASED")){
dictionaries["shop"+x.Id].Add(x.timestamp, x.item);
}
if ((x.Type.Contains("SOLD")){
dictionaries["sell"+x.Id].Add(x.timestamp, x.item);
}
if ((x.Type.Contains("DESTROYED")){
dictionaries["de"+x.Id].Add(x.timestamp, x.item);
}
}

IEnumerable <T> with anonymous methods

I dont know how to get rid of this error ?
Error 1 Using the generic type 'System.Collections.Generic.IEnumerable' requires 1 type arguments C:\Users\huzaifa.gain\documents\visual studio 2010\Projects\VendInvoiceImport\VendInvoiceImport\Program.cs 34 24 VendInvoiceImport
private static IEnumerable<string , string > DistinctInvoiceNumber(DataTable VendorInvoiceStagingTable)
{
var InvoiceLinecollection = VendorInvoiceStagingTable.AsEnumerable().Select(t => new { number = t.Field<string>(VendInvoice.Number),LineNumber = t.Field<string>(VendInvoice.LineNumber)}).Distinct();
return InvoiceLinecollection;
}
Your Linq query returns an sequence of anonymous type, but methods can't return anonymous types. You have several options:
return an IEnumerable<Tuple<string, string>>
private static IEnumerable<Tuple<string, string>> DistinctInvoiceNumber(DataTable VendorInvoiceStagingTable)
{
var InvoiceLinecollection = VendorInvoiceStagingTable
.AsEnumerable()
.Select(t => Tuple.Create(t.Field<string>(VendInvoice.Number), t.Field<string>(VendInvoice.LineNumber)))
.Distinct();
return InvoiceLinecollection;
}
return a IDictionary<string, string> as suggested in another answer (assuming your query doesn't return duplicate keys)
private static IDictionary<string, string> DistinctInvoiceNumber(DataTable VendorInvoiceStagingTable)
{
var InvoiceLinecollection = VendorInvoiceStagingTable
.AsEnumerable()
.Select(t => Tuple.Create(t.Field<string>(VendInvoice.Number), t.Field<string>(VendInvoice.LineNumber)))
.Distinct()
.ToDictionary(t => t.Item1, t => t.Item2);
return InvoiceLinecollection;
}
create a class for this purpose with 2 string properties and return a sequence of that class
private static IEnumerable<InvoiceLine> DistinctInvoiceNumber(DataTable VendorInvoiceStagingTable)
{
var InvoiceLinecollection = VendorInvoiceStagingTable
.AsEnumerable()
.Select(t => new InvoiceLine(t.Field<string>(VendInvoice.Number), t.Field<string>(VendInvoice.LineNumber)))
.Distinct();
return InvoiceLinecollection;
}
Why you do not use Dictionary<string, string> instead?
private static Dictionary<string , string > DistinctInvoiceNumber(DataTable VendorInvoiceStagingTable)
{
var InvoiceLinecollection = VendorInvoiceStagingTable.AsEnumerable().Select(t => new { number = t.Field<string>(VendInvoice.Number),LineNumber =
t.Field<string>(VendInvoice.LineNumber)}).ToDictionary();
return InvoiceLinecollection;
}

Categories