I have a List which I would like to populate with different types of objects, trying to do it with object\dynamic, but it doesn't, even when casting.
using asp.net core.
See my code:
public Dictionary<string, Employee> getEmployees(); //This method returns a dictionary of string as a key and Employee as a value.
public Dictionary<string, customer>()> getCustomers(); //same principal
public List<Dictionary<string, object>> getDifferentItems()
{
List<Dictionary<string, object>> listOfItems = new List<Dictionary<string, object>>();
listOfItems.add(getEmployees()); //Error
listOfItems.add(getCustomers()); //Error
return listOfItems;
}
Depending on what you are trying to do, I can see two solutions:
Create a list of TWO different dictionaries
public Dictionary<string, Employee> getEmployees() {
return new Dictionary<string, Employee>();
}
public Dictionary<string, Customer> getCustomers() {
return new Dictionary<string, Customer>();
}
public List<Dictionary<string, object>> getDifferentItems()
{
List<Dictionary<string, object>> listOfItems = new List<Dictionary<string, object>>();
listOfItems.Add(this.getEmployees().ToDictionary(entry => (string)entry.Key,
entry => (object)entry.Value));
listOfItems.Add(this.getCustomers().ToDictionary(entry => (string)entry.Key,
entry => (object)entry.Value));
return listOfItems;
}
Create one dictionary with all the values
public Dictionary<string, Employee> getEmployees() {
return new Dictionary<string, Employee>();
}
public Dictionary<string, Customer> getCustomers() {
return new Dictionary<string, Customer>();
}
public Dictionary<string, object> getDifferentItems()
{
Dictionary<string, object> listOfItems = new Dictionary<string, object>();
foreach (var entry in getEmployees()) {
listOfItems.Add(entry.Key, entry.Value);
}
foreach (var entry in getCustomers()) {
listOfItems.Add(entry.Key, entry.Value);
}
return listOfItems;
}
There are a couple of issues here, both related to variance.
This won't work because List<T>, or any other class in .NET for that matter, does not support variance.
In other words T has to be a specific type, and does not respect inheritance / substitutability as with non-generic types.
Similarly, for Dictionary<TKey, TValue>, TValue is not variant, so you can't simply use object as the value.
IEnumerable<out T> on the other hand is covariant so you could do this:
public IEnumerable<IDictionary> getDifferentItems()
{
yield return getEmployees();
yield return getCustomers();
}
IDictionary is used, as it is the only common ancestor (other than object) to Dictionary<string, Employee> and Dictionary<string, Customer>.
This may satisfy your requirements, but you don't make clear whay you are trying to achive with your getDifferentItems method.
More information on variance can be found here.
I'd personally make an interface, such as IPerson that has all the properties of Employees and Customers, such as Name, Address, ID, etc.
Set up your Customer and employee classes to implement IPerson
Then use a IPerson in your dictionary and you can add to the objects to that.
Here's some code:
public class Employee : IPerson
{
public int ID { get; set; }
public string Name { get; set; }
}
public class Customer : IPerson
{
public int ID { get; set; }
public string Name { get; set; }
}
public interface IPerson
{
int ID { get; set; }
string Name { get; set; }
}
public class Test
{
public void MyTest()
{
List<Dictionary<string, IPerson>> listOfItems = new List<Dictionary<string, IPerson>>();
Dictionary<string, IPerson> myEmployees = new Dictionary<string, IPerson>();
string someString = "blah";
Employee e = new Employee();
e.Name = "Bob";
e.ID = 1;
myEmployees.Add(someString, e);
Dictionary<string, IPerson> myCustomers = new Dictionary<string, IPerson>();
string someOtherString = "blah";
Customer c = new Customer();
c.Name = "Robert";
c.ID = 2;
myCustomers.Add(someOtherString, c);
listOfItems.Add(myEmployees);
listOfItems.Add(myCustomers);
}
}
Here is another solution :
public class Test
{
Dictionary<string, object> listOfItems = new Dictionary<string, object>();
List<Employee> employees = new List<Employee>();
List<customer> customers = new List<customer>();
public Dictionary<string, object> getEmployees()
{
return employees.GroupBy(x => x.name, y => (object)y).ToDictionary(x => x.Key, y => y.FirstOrDefault());
}//This method returns a dictionary of string as a key and Employee as a value.
public Dictionary<string, object> getCustomers()
{
return customers.GroupBy(x => x.name, y => (object)y).ToDictionary(x => x.Key, y => y.FirstOrDefault());
} //same principal
public Dictionary<string, object> getDifferentItems()
{
listOfItems = getEmployees();
listOfItems.Concat(getCustomers());
return listOfItems;
}
}
public class Employee
{
public string name { get;set;}
}
public class customer
{
public string name { get;set;}
}
Related
I have the following function, which takes a Dictionary and a List, matches rows in each of those and returns another Dictionary based on matcing items.
Is there a better way (code and performance -wise) to achieve the same result?
public sealed class ProdIds
{
public List<ProdID> Items { get; set; }
}
public sealed class ProdID
{
public string SpecialId { get; set; }
public int ItemId { get; set; }
}
Simplified view of the entries:
names: {100, "Name1"}, {333, "Name3"}, {212, "Name55"}, {99, "NameABC"}, ...
ids: {"SP44", 212}, {"SP33", 333}, {"SP11", 100}, {"SP9", 99}, ...
private static Dictionary<string, string> CreateMatchedDictionary (IReadOnlyDictionary<int, string> names, List<ProdIds> ids)
{
var dic = new Dictionary<string, string>();
foreach (var name in names)
{
foreach (var id in ids)
{
if (name.Key == id.Items[0].ItemId)
{
dic.Add(id.Items[0].SpecialId, name.Value);
}
}
}
return dic;
}
What I want to be returned here, is a new Dictionary which would look similar to this:
dic: {"SP44", "Name55"}, {"SP33", "Name3"}, {"SP11", "Name1"}, {"SP9", "NameABC"}, ...
The main performance problem is that you're looping through the names dictionary instead of taking advantage of the built-in O(1) lookup:
private static Dictionary<string, string> CreateMatchedDictionary (IReadOnlyDictionary<int, string> names, List<ProdIds> ids)
{
var dic = new Dictionary<string, string>();
foreach (var id in ids)
{
string name = null;
if (names.TryGetValue(id.Items[0].ItemId, out name)
{
dic.Add(id.Items[0].SpecialId, name);
}
}
return dic;
}
You could use Linq to make the code more concise, but it's not going to improve performance and might make debugging harder.
I am trying to figure out if there is a way to generalize a function that takes a Hashset of two unrelated objects with similar attributes. I have some sample code below:
private IList<IDictionary<string, string>> BuildDictionary(HashSet<ClassA> ClassA)
{
IList<IDictionary<string, string>> data = new List<IDictionary<string, string>>();
foreach (var a in ClassA)
{
Dictionary<string, string> aDictionary = new Dictionary<string, string>();
aDictionary.Add(a.Code, a.Code + "," + a.Name);
data.Add(aDictionary);
}
return data;
}
private IList<IDictionary<string, string>> BuildDictionary(HashSet<ClassB> ClassB)
{
IList<IDictionary<string, string>> data = new List<IDictionary<string, string>>();
foreach (var b in ClassB)
{
Dictionary<string, string> bDictionary = new Dictionary<string, string>();
bDictionary.Add(b.Code, b.Code + "," + b.Name);
data.Add(bDictionary);
}
return data;
}
Thus as evident from the code, the two classes are not related but they both are in a HashSet and contain similar attributes (code, name). I have tried using the generic T but that failed due to the fact that I don't have the generic class T created. Would there be anyway to get around this issue without creating a new class?
If your source classes are sealed or can't be modified to a common interface, you can use accessors for the parts that are needed, as one might do in most LINQ queries.
Here's an example implementation. Note that toKey() and toMemberValue() could be named more appropriately, but this is enough to replicate what you are doing for any class where you can specify a lambda to retrieve the relevant property, and isn't dependent upon the class necessarily having the same property names so long as the lambda is written accordingly. Main() shows what it would look like to use this method for both cases.
public IList<IDictionary<string, string>> BuildDictionary<T>(HashSet<T> sourceSet, Func<T, string> toKey, Func<T, string> toMemberValue)
{
IList<IDictionary<string, string>> data = new List<IDictionary<string, string>>();
foreach (var element in sourceSet)
{
Dictionary<string, string> newLookup = new Dictionary<string, string>();
newLookup.Add(toKey(element), $"{toKey(element)},{toMemberValue(element)}");
data.Add(newLookup);
}
return data;
}
void Main()
{
HashSet<ClassA> setOfAs = new HashSet<ClassA>(new[] { new ClassA { Code = "foo", Name = "bar" }, new ClassA { Code = "foo2", Name = "bar2" } });
HashSet<ClassB> setOfBs = new HashSet<ClassB>(new[] { new ClassB { Code = "foo", Name = "bar" }, new ClassB { Code = "foo2", Name = "bar2" } });
var lookupOfAs = BuildDictionary(setOfAs, x => x.Code, x => x.Name);
var lookupOfBs = BuildDictionary(setOfBs, x => x.Code, x => x.Name);
}
// Define other methods and classes here
public class ClassA
{
public string Code { get; set; }
public string Name { get; set; }
}
public class ClassB
{
public string Code { get; set; }
public string Name { get; set; }
}
If you own the source code to both types you can implement a common interface.
private IList<IDictionary<string, string>> BuildDictionary<T>(HashSet<T> someHashSetOfTs) where T : ICommon
{
IList<IDictionary<string, string>> data = new List<IDictionary<string, string>>();
foreach (var a in someHashSetOfTs)
{
Dictionary<string, string> aDictionary = new Dictionary<string, string>();
aDictionary.Add(a.Code, a.Code + "," + a.Name);
data.Add(aDictionary);
}
return data;
}
Interface definition
public interface ICommon {
string Code {get; }
string Name {get; }
}
And now apply ICommon to both types ClassA and ClassB.
I am new in the dictionary datatype in C#. I got this model item:
public Dictionary<int, string> language { get; set; }
public string languageChoice { get; set; }
Then in my controller I got this:
[Route("{id}/settings")]
[HttpGet]
public async Task<HttpResponseMessage> GetProjectSettings(Guid id)
{
var projectSettings = new ProjectSettings
{
Id = id,
language = new Dictionary<int, string>() {
{1,"English"},
{2,"Spanish"}},
languageChoice = //get language by ID
};
if (projectSettings != null)
{
return Request.CreateResponse<ProjectSettings>(HttpStatusCode.OK, projectSettings);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Project not found");
}
}
I want to give the json object the integer and not the String of the language. How can I do that?
Kind regards
If you don't want to change your existing Dictionary<int, string> then you can just create a new Dictionary<int, int> from it.
var alteredDictionary = languages.ToDictionary(x => x.Key, x => x.Key);
Then do
var projectSettings = new ProjectSettings
{
Id = id,
language = new Dictionary<int, string>() {
{1,"English"},
{2,"Spanish"}},
languageChoice = alteredDictionary[1]// optional .ToString() if you want string
};
Where 1 is the language Id you want.
Is there an automagic (automapper?) way to map an entity to a runtime created dynamic object with properties passed as parameters? I want to do an API where the clients can select the properties of the entities they want to fetch.
I mean:
class Patient
{
public int PatientId{ get; set; }
public string Name{ get; set; }
public string LastName{ get; set; }
public string Address{ get; set; }
...
}
getPatient(string[] properties)
{
//Return an object that has the properties passed as parameters
}
Imagine you only want to fetch a PatientDTO with PatientId and Name:
getPatient(new string[]{"PatientId", "Name"}
should return
{
"PatientId": "1234",
"Name": "Martin",
}
and so on.
For now I'm doing it with Dictionary, but probably there is a better way. This is my approach:
For a single object:
public static Dictionary<string, object> getDTO(string[] properties, T entity)
{
var dto = new Dictionary<string, object>();
foreach (string s in properties)
{
dto.Add(s, typeof(T).GetProperty(s).GetValue(entity));
}
return dto;
}
For a list of objects:
public static List<Dictionary<string, object>> getDTOList(string[] properties, List<T> TList)
{
var dtoList = new List<Dictionary<string, object>>();
foreach(T entity in TList)
{
dtoList.Add(getDTO(properties, entity));
}
return dtoList;
}
Thank you.
How about creating a new dynamic object based solely on the specified property fields and returning the dynamic?
You will need to add using statements for: System.Dynamic and System.ComponentModel for the following to work.
public static dynamic getDTO(object entity, string[] properties)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (var p in properties)
{
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(entity.GetType()))
{
if (property.Name == p)
{
expando.Add(p, property.GetValue(entity));
break;
}
}
}
return expando as ExpandoObject;
}
Calling this method would look something like this:
var patient = new Patient() { PatientId = 1, Name = "Joe", LastName = "Smith", Address = "123 Some Street\nIn Some Town, FL 32333" };
var propList = new string[] { "PatientId", "Name", "Address" };
dynamic result = getDTO(patient, propList);
Console.WriteLine("Id:{0} Name: {1}\nAddress: {2}", result.PatientId, result.Name, result.Address);
Console.ReadLine();
I have Struct
struct User
{
public int id;
public Dictionary<int, double> neg;
}
List<User> TempUsers=new List<users>();
List<User> users = new List<User>();
my Problem is, when I run this code
TempUsers=users.ToList();
TempUsers[1].neg.Remove(16);
neg dictionary in users aslo remove key with value=16
That is because the Dictionary is a reference type. You should clone it, for sample:
class User : IClonable
{
public int Id { get; set; }
public Dictionary<int, double> Neg { get; set; }
public object Clone()
{
// define a new instance
var user = new User();
// copy the properties..
user.Id = this.Id;
user.Neg = this.Neg.ToDictionary(k => k.Key,
v => v.Value);
return user;
}
}
You shouldn't use a struct in a type like this. In this link, there is a good explanation about when and how you should use a struct.
Dictionary is a reference type. You should clone you dictionary:
this is an example:
struct User : ICloneable
{
public int id;
public Dictionary<int, double> neg;
public object Clone()
{
var user = new User { neg = new Dictionary<int, double>(neg), id = id };
return user;
}
}