How to get keys of objects as key value pairs? - c#

I have class object and I need to store its values and keys in specific format.
public class AppSettings
{
public int TokenLifeTime { get; set; } = 450;
public List<string> Urls { get; set; } = new List<string>
{
"www.google.com",
"www.hotmail.com"
};
public List<ServersList> ServersList { get; set; } = new List<ServersList>
{
new ServersList {IsHttpsAllowed = false},
new ServersList {IsHttpsAllowed = true}
};
}
public class ServersList
{
public bool IsHttpsAllowed { get; set; }
}
I want to get keys in this format.
"AppSettings:TokenLifeTime" , 450
"AppSettings:Urls:0", "www.google.com"
"AppSettings:Urls:1", "www.hotmail.com"
"AppSettings:ServersList:0:IsHttpsAllowed", false
"AppSettings:ServersList:1:IsHttpsAllowed", true
Is there any way to get all keys as string recursively regardless of object depths. Above code is just an example in real case I have long list and lot more data.

I don't think that there is anything out of the box for this.
You would need to create something yourself and define your rules.
In its more primitive form, I'd start with this:
Type t = typeof(AppSettings);
Console.WriteLine("The {0} type has the following properties: ",
t.Name);
foreach (var prop in t.GetProperties())
Console.WriteLine(" {0} ({1})", prop.Name,
prop.PropertyType.Name);
Then add a rule for IEnumerable to handle them in iterations and so forth for objects and primitive value types.

I have a couple of examples for you:
Option 1:
public class AppSettings
{
public int TokenLifeTime { get; set; } = 450;
public Dictionary<string, ServersList> Urls { get; set; } = new Dictionary<string, ServersList>
{
{"www.google.com", new ServersList {IsHttpsAllowed = false}},
{ "www.hotmail.com", new ServersList {IsHttpsAllowed = true}}
};
}
public class ServersList
{
public bool IsHttpsAllowed { get; set; }
}
This option would group the values together but you would lose 'int' based index. Not sure if that is important.
Option 2:
public class AppSettings
{
public int TokenLifeTime { get; set; } = 450;
public List<KeyValuePair<string, ServersList>> Urls { get; set; } = new List<KeyValuePair<string, ServersList>>
{
new KeyValuePair<string, ServersList>("www.google.com",new ServersList {IsHttpsAllowed = false}),
new KeyValuePair<string, ServersList>("www.hotmail.com", new ServersList {IsHttpsAllowed = true})
};
public List<ServersList> ServersList { get; set; } = new List<ServersList>
{
new ServersList {IsHttpsAllowed = false},
new ServersList {IsHttpsAllowed = true}
};
}
public class ServersList
{
public bool IsHttpsAllowed { get; set; }
}
This option will retain 'int' based indexing and the values are still grouped. But feels clunky...
Option 3: (the one I would go with)
public class AppSettings
{
public int TokenLifeTime { get; set; } = 450;
public List<Server> ServersList { get; set; } = new List<Server>
{
new Server { Url = "www.google.com", IsHttpsAllowed = false},
new Server { Url = "www.hotmail.com", IsHttpsAllowed = true}
};
}
public class Server
{
public string Url { get; set; }
public bool IsHttpsAllowed { get; set; }
}
This option still gives you 'int' based indexing and it groups the data together (as it should be from what I understand in the example).

Related

Something is getting wrong with adding a list to existing List

I'm trying to realize the listBox with List where i getting some variable.
And when i wonna to add a new "Object" to static List i getting a NullReferenceException
This is my code where i adding a new List
if (EventArgsIn.Message.Chat.Id == MainChatId)
{
if (EventArgsIn.Message.ReplyToMessage != null)
{
var _tempMessage = new listBoxMessage()
{
From = EventArgsIn.Message.From.Username,
FromId = EventArgsIn.Message.From.Id,
MessageId = EventArgsIn.Message.MessageId,
MessageText = EventArgsIn.Message.Text,
MessageIdReply = 0
};
tempMessageMain.Add(_tempMessage);
} else
{
var _tempMessage = new listBoxMessage() {
From = EventArgsIn.Message.From.Username,
FromId = EventArgsIn.Message.From.Id,
MessageId = EventArgsIn.Message.MessageId,
MessageText = EventArgsIn.Message.Text,
MessageIdReply = 0
};
tempMessageMain.Add(_tempMessage);
}
}
And here is my static List
public static List<listBoxMessage> tempMessageMain;
A-a-and my class where i doing Template
public class listBoxMessage
{
public listBoxMessage()
{
}
public string From { get; set; }
public int FromId { get; set; }
public int MessageId { get; set; }
public string MessageText { get; set; }
public int MessageIdReply { get; set; }
}
}
This is test code*
You declared a listbox with next line:
public static List<listBoxMessage> tempMessageMain;
The value of tempMessageMain is still null.
Now you have to create a new instance of tempMessageMain:
public static List<listBoxMessage> tempMessageMain = new List<listBoxMessage>();

Need help using Linq to transform a list into a different list

Lets say I have a list that contains 1 record:
[
{
"AccountNumber": 1234,
"eDocConfirms": true,
"eDocStatements": true,
"eDocTaxforms": false
}
]
This list is a strongly typed object with these properties:
public int AccountNumber { get; set; }
public bool? eDocConfirms { get; set; }
public bool? eDocStatements { get; set; }
public bool? eDocTaxforms { get; set; }
Using LINQ, I'd like to turn it into a list that looks like this:
[
{
"AccountNumber": 1234,
"EDocumentTypeName ": "Confirms"
},
{
"AccountNumber": 1234,
"EDocumentTypeName": "Statements"
}
]
This new list will a list of a different type:
public class DeliveryPreference
{
public int AccountNumber { get; set; }
public string EDocumentTypeName { get; set; }
}
Note that Taxforms was not included in the new list because it was set to false in the first list.
I know I could easily do this with some loops, but I would prefer using LINQ.
I understand that Stack Overflow prefers that I show what I have tried, but I am having trouble wrapping my brain around this.
For this case I would use additional function
public static IEnumerable<string> GetTrueProperties(Data t)
{
if (t.eDocConfirms == true) yield return "Confirms";
if (t.eDocStatements == true) yield return "Statements";
if (t.eDocTaxForms == true) yield return "Tax";
}
simply because it is an object and not a dictionary; else you could dynamically select properties which are true(or you could use reflection, but I think it would be too much here, since you have strongly typed object).
then it would look like
var list = new List<Data> {
new Data
{
AccountNumber = 1,
eDocConfirms = true,
eDocStatements = true,
eDocTaxForms = false
}
};
list.SelectMany(item => GetTrueProperties(item).Select(p => new DeliveryPreference
{
AccountNumber = item.AccountNumber,
EDocumentTypeName = p
}));
This is very ugly code, but it works. It should be easy to comprehend. Reflection can be extracted to a new function.
using System;
using System.Linq;
public class Program
{
public class Account {
public int AccountNumber { get; set; }
public bool? eDocConfirms { get; set; }
public bool? eDocStatements { get; set; }
public bool? eDocTaxforms { get; set; }
}
public class DeliveryPreference
{
public int AccountNumber { get; set; }
public string EDocumentTypeName { get; set; }
}
public static void Main()
{
var acc = new Account {
AccountNumber = 10,
eDocConfirms = true,
eDocStatements = false,
eDocTaxforms = true
};
var transformed = acc.GetType()
.GetProperties()
.Where(p => p.PropertyType == typeof(bool?)
&& ((bool?)p.GetValue(acc)).HasValue
&& ((bool?)p.GetValue(acc)).Value)
.Select(p => new DeliveryPreference {
AccountNumber = acc.AccountNumber,
EDocumentTypeName = p.Name.Substring(4)
});
foreach (var t in transformed) {
Console.WriteLine(t.AccountNumber);
Console.WriteLine(t.EDocumentTypeName);
}
}
}

Polymorphism not working on collections elements using MessagePack-Csharp nuget

I'm not being able to deserialize a collection of elements where the instances have a Inheritance relationship between them.
Does anyone came across this issue?
So my use case is this:
My model is similiar to this:
[DataContract]
public class Item
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public bool Valid { get; set; }
}
[DataContract]
public class IntermediateItem : Item
{
[DataMember]
public int Priority { get; set; }
}
[DataContract]
public class ExtendedItem : IntermediateItem
{
[DataMember]
public int Count { get; set; }
[DataMember]
public ItemsCollection Childs { get; set; }
}
And Items Collection is something like this:
[DataContract]
public class ItemsCollection : Collection<Item>
{
}
The setup that I have made to ensure the proper deserialization is:
Defining the CollectionFormatterBase:
public class ItemCollectionFormatterBase : CollectionFormatterBase<Item, ItemsCollection>
{
protected override ItemsCollection Create(int count)
{
return new ItemsCollection();
}
protected override void Add(ItemsCollection collection, int index, Item value)
{
collection.Add(value);
}
}
The example that is not working, and not working I mean, the deserialized instances are all of base type, some how the inheritance relationship got lost in the serialization.
Example:
MessagePack.Resolvers.CompositeResolver.RegisterAndSetAsDefault(new[] { new ItemCollectionFormatterBase() }, new[] { StandardResolver.Instance });
ExtendedItem instance = new ExtendedItem()
{
Id = 1,
Name = "Extended Item",
Priority = 121,
Valid = true,
Count = 10,
Childs = new ItemsCollection(new List<Item>() { new Item() { Id = 1 }, new IntermediateItem() { Priority = 10 }, new ExtendedItem() { Count = 10 } })
};
byte[] bytes = MessagePackSerializer.Serialize(instance);
using (FileStream file = new FileStream(this.filePath.AbsolutePath, FileMode.Create))
{
await file.WriteAsync(bytes , 0, payload.Length);
await file.FlushAsync();
}
using (FileStream file = new FileStream(testsFolder + #"\ExtendedItem.msgPack-csharp.dat", FileMode.Open))
{
file.Seek(0, SeekOrigin.Begin);
deserializedInstance = MessagePackSerializer.Deserialize<ExtendedItem>(file);
}
looking at the deserializedInstance Childs elements they all are from Item Type.
Can you tell me what I'm doing wrong ? What is missing ?
A small update regarding Item definition:
[DataContract]
[KnownType(typeof(IntermediateItem))]
[KnownType(typeof(ExtendedItem))]
public class Item
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public bool Valid { get; set; }
}
This also does not work. :(
Well looks like MessagePackSerializer static type as a static inner class called Typeless and that solve my problem:
With a instance of a ExtendedItem:
ExtendedItem instance = new ExtendedItem()
{
Id = 1,
Name = "Extended Item",
Priority = 121,
Valid = true,
Count = 10,
Childs = new ItemsCollection(new List<Item>() { new Item() { Id = 1 }, new IntermediateItem() { Priority = 10 }, new ExtendedItem() { Count = 10 } })
};
I was able to serialize that and deserialize with success !
byte[] bytes = MessagePackSerializer.Typeless.Serialize(instance);
await fileManager.WriteAsync(bytes);
ExtendedItem deserializedInstance = null;
deserializedInstance = MessagePackSerializer.Typeless.Deserialize(bytes) as ExtendedItem;
despite the serialization and deserialization worked on .NET this sample did not work when deserializing in nodejs with msgpackjs package.

C# - Adding data to list inside list

How can I add the following data on the table into a list called Vehicles?
public class criterias
{
public double values { get; set; }
public double time { get; set; }
}
public class movChannels
{
public string name { get; set; }
public IList<criterias> criteria = new List<criterias>();
}
public class stepsList
{
public string steps { get; set; }
public IList<movChannels> stepChannelsCriteria = new List<movChannels>();
}
public class vehicles
{
public int vehID { get; set; }
public string vehDescription { get; set; }
public IList<stepsList> vehValCriteria = new List<stepsList>();
}
Now, how can I add the data that I have in the table shown into a list called Vehicles? I will create other vehicles later...
You had several bad decisions, some were design flaws and some were minor C# naming convention violations.
Couple of worth mentions flaws:
vehID should have been a string and not int (Example "XPT")
Movment has Name, Value and Time. It doesn't have a list of Values and Times.
Creation:
List<Vehicle> vehicles = new List<Vehicle>();
Vehicle vehicle = new Vehicle()
{
Id = "XPT",
Description = "Average Car",
Steps = new List<Step>()
{
new Step() {
Name = "move car",
Movements = new List<Movement>()
{
new Movement("engage 1st gear", 1, 1),
new Movement("reach 10kph", 10, 5),
new Movement("maintain 10kph", 10, 12),
}
},
new Step() {
Name = "stop car",
Movements = new List<Movement>()
{
new Movement("reach 0kph", 10, 4),
new Movement("put in neutral", 0, 1),
new Movement("turn off vehicle", 0, 0),
}
}
}
};
vehicles.Add(vehicle);
Entities:
public class Movement
{
public string Name { get; set; }
public double Values { get; private set; }
public double Time { get; private set; }
public Movement(string name, double values, double time)
{
Name = name;
Values = values;
Time = time;
}
}
public class Step
{
public string Name { get; set; }
public IList<Movement> Movements { get; set; }
}
public class Vehicle
{
public string Id { get; set; } // Should be changed to string
public string Description { get; set; }
public IList<Step> Steps { get; set; }
}
You should create your classes like the following:
public class criterias
{
public double values { get; set; }
public double time { get; set; }
}
public class movChannels
{
public movChannels
{
criteria = new List<criterias>();
}
public string name { get; set; }
public IList<criterias> criteria { get; set; }
}
public class stepsList
{
public stepsList
{
stepChannelsCriteria = new List<movChannels>();
}
public string steps { get; set; }
public IList<movChannels> stepChannelsCriteria { get; set; }
}
public class vehicles
{
public vehicles
{
vehValCriteria = new List<stepsList>();
}
public int vehID { get; set; }
public string vehDescription { get; set; }
public IList<stepsList> vehValCriteria { get; set; }
public movChannels movments { get; set; }
}
What about that?
public class VehiclesViewModel
{
public List<vehicles> Vehicles { get; private set; }
public void Initalize()
{
this.Vehicles = new List<vehicles>();
var vehicle = new vehicles
{
vehID = 1,
vehDescription = "firstDescription",
};
var stepsList = new stepsList
{
steps = "firstStep",
};
var movChannel = new movChannels
{
name = "firstChannel",
};
var criteria = new criterias
{
values = 0.5,
time = 0.5
};
movChannel.criteria.Add(criteria);
stepsList.stepChannelsCriteria.Add(movChannel);
vehicle.vehValCriteria.Add(stepsList);
this.Vehicles.Add(vehicle);
}
}
it seems in your table the VehicleId is of type string. Make sure your VehicleId property in Vehicle class also matches the same.
You can use the collection initializers to set the values of child objects like this way:
var data = new vehicles()
{
vehID = 1,
vehDescription = "Average Car",
vehValCriteria = new List<stepsList>()
{
new stepsList()
{
steps = "Move car",
stepChannelsCriteria = new List<movChannels>()
{
new movChannels()
{
name = "engage firstgear",
criteria = new List<criterias>()
{
new criterias()
{
values = 1,
time = 1
},
}
},
new movChannels()
{
name = "reach 10kph",
criteria = new List<criterias>()
{
new criterias()
{
values = 10,
time = 5
},
}
},
new movChannels()
{
name = "maintain 10kph",
criteria = new List<criterias>()
{
new criterias()
{
values = 10,
time = 12
},
}
}
}
},
new stepsList()
{
steps = "stop car",
stepChannelsCriteria = new List<movChannels>()
{
new movChannels()
{
name = "reach okph",
criteria = new List<criterias>()
{
new criterias()
{
values = 10,
time = 4
},
}
},
new movChannels()
{
name = "put in neutral",
criteria = new List<criterias>()
{
new criterias()
{
values = 0,
time = 1
},
}
},
new movChannels()
{
name = "turn off vehicle",
criteria = new List<criterias>()
{
new criterias()
{
values = 0,
time = 0
},
}
}
}
}
}
};
You can fill your list by moving from top to bottom, like
Create Criterias List then Create movChannel object and add that list
to Criterias object and so on
However if you want to avoid this way, there is another way. If you are using Linq To List then follow this
Get a simple flat object to a list object
var TableData = db.Tablename.Tolist();
Then fill your own object like this
Vehicles finalList = TableData.Select(a => new Vehicles()
{
vehID = a.Id,
vehDescription = a.des,
vehValCriteria = TableData.Where(b => b.StepslistId == a.StepslistId)
.Select(c => new StepsList()
{
steps = c.Steps,
stepChannelsCriteria = TableData.Where(d => d.channelId == c.channelId)
.select(e => new MovChannels()
{
name = e.name,
criteria = TableData.Where(f => f.criteriasId = e.criteriasId)
.Select(g => new Criterias()
{
values = g.Values,
time = g.Time
}).ToList()
}).ToList()
}).ToList()
}).ToList();
This is standard way to fill list within list

Seed list inside an empty list

I'm working with KnockoutMVC and it requires strongly type models to use inside the VIEW. I have tried multiple variations of the examples on KnockoutMVC's site including using ENUMS and still could not get it to work. Perhaps this is a problem with the setup of my models.
MODELS
public class PhoneNumber
{
public List<NumberTypeClass> Types { get; set; }
//public NumberType enumType { get; set; }
//public enum NumberType
//{
// Work,
// Home,
// Mobile,
// Fax
//}
private string _number;
[StringLength(14, MinimumLength = 10, ErrorMessage = "Please use (123) 456-7890 format"), Required]
public string Number
{
get
{
this._number = BeautifyPhoneNumber(this._number);
return this._number;
}
set
{
this._number = value;
}
}
public string Extension { get; set; }
public static String BeautifyPhoneNumber(string numberToBeautify)
{
//beautifyNumberCode
}
}
public class NumberTypeClass
{
public int Id { get; set; }
public string NumberType { get; set; }
}
public class VendorsEditorVendorModel
{
public string FirstName {Get;set;}
public string LastName {get;set;}
public List<Address> Address {get;set;}
public List<PhoneNumber> Phones {get;set;}
}
public class VendorsEditorModel
{
public List<VendorsEditorVendorModel> Vendors {get;set;}
}
CONTROLLER
public class VendorsEditorController : BaseController
{
public ActionResult CreateVendors()
{// VendorsEditor/CreateVendors
var vendor = new VendorsEditorModel();
vendor.Vendors = new List<VendorsEditorVendorModel>();
vendor.Vendors[0].Phones[0].Types = new List<NumberTypeClass>
{
new NumberTypeClass{Id = 0, TypeName = "Mobile"},
new NumberTypeClass{Id = 0, TypeName = "Work"},
new NumberTypeClass{Id = 0, TypeName = "Home"}
};//this throws an error because there is no Vendors[0] ...but how would i populate this list for every Vendor?
return View(vendor);
}
}
You cannot call an empty collection by index [x]. You need to fill your collection from a database or what not before you can access items in it. If you are just trying to add items to a collection, this is how you do it:
var vendor = new VendorsEditorModel
{
Vendors = new List<VendorsEditorVendorModel>
{
new VendorsEditorVendorModel
{
Phones = new List<PhoneNumber>
{
new PhoneNumber
{
Types = new List<NumberTypeClass>
{
new NumberTypeClass {Id = 0, NumberType = "Mobile"}
}
}
}
}
}
};
If you just want to add the types to an already populated collection, you can do the following:
foreach (var phone in vendor.Vendors.SelectMany(item => item.Phones))
{
phone.Types = new List<NumberTypeClass>
{
new NumberTypeClass{Id = 0, NumberType = "Mobile"},
new NumberTypeClass{Id = 0, NumberType = "Work"},
new NumberTypeClass{Id = 0, NumberType = "Home"}
};
}

Categories