C# Multiple Keys to one Value - c#

I am looking for a C# container that can map multiple keys to a single object. For example: a single person can be referenced by his English name, or his Spanish name. I want to do this so that I don't have to create multiple copies of Dictionaries, and when I add/remove from the structure, I only have to add/remove once. Does such a structure exist?

Yes it exists: Dictionary<TKey, TValue>
There is no reason why you can't add a single object instance with multiple keys:
public class Person
{
public string EnglishName { get; set; }
public string SpanishName { get; set; }
}
public static class PersonDictExtensions
{
public static void AddPerson(this IDictionary<string, Person> persons, Person person)
{
persons.Add(person.EnglishName, person);
persons.Add(person.SpanishName, person);
}
public static void RemovePerson(this IDictionary<string, Person> persons, Person person)
{
foreach (var item in persons.Where(x => object.ReferenceEquals(x.Value, person)).ToList())
{
persons.Remove(item.Key);
}
}
}
var person = new Person { EnglishName = "Foo", SpanishName = "Bar" };
var dict = new Dictionary<string, Person>();
dict.AddPerson(person);
dict.RemovePerson(person);
EDIT
Ups I understand: only one add and remove? Hm. Doesn't know that such a structure exists. Maybe you can add an extension method to handle that cases.
I changed the code...

Related

Is there a way of writing code similar to the syntax: class.method("variable").returnedVariable

I am trying to improve my understanding of C#. Is there a way to write C# code in the format:
string name = Person("Dave").name;
int age = Person("Dave").age;
I know that this can be done in Javscript and I am aware this can be done in C# using a dictionary similar to:
int age = Person["Dave"].age;
or
int age = Person.age("Dave");
My understanding is that the dictionary option will just return a value and cannot run a method for get the value "age"
I have seen a few examples of code similar to the first two examples but do not understand how this would be written or if it is even possible.
If you want to have such a syntax Person("Dave").name - you can implement a helper:
namespace MyClasses {
...
public static class PersonHelper {
...
public static Person Person(string name) {
//TODO: having name you should return Person instance,
// e.g. with a help of some dictionary:
return Person.AllPersons.TryGetValue(name, out var result)
? result
: null;
}
}
Let's implement this AllPersons dictionary within Person:
public class Person {
// Simplest, but not thread safe
private static Dictionary<string, Person> s_AllPersons = new
Dictionary<string, Person>();
public Person(string name) {
// When Person created we put the instance into the dictionary
s_AllPersons.Add(name, this);
Name = name;
}
public string Name {get;}
public static IReadOnlyDictionary<string, Person> AllPersons => s_AllPersons;
...
}
Then add using static to get rid of pesky PersonHelper name:
using static MyClasses.PersonHelper;
And we've done:
string name = Person("Dave").Name;
Here Person("Dave") will be treated as MyClasses.PersonHelper.Person("Dave") which return Person class instance for us of which we read Name property (or field)
You can try to do this via Properties and a static Dictionary:
class Person {
static public Dictionary<string, Person> Persons {get; set;};
public string Name {get; set; }
public Person()
{
if ( null == Persons ) Persons = new Dictionary<string, Person>();
}
}
// Not tested, but shoud work
Person.Persons("dave")?.Name
But it will be not the same as in Javascript or in Python.

How to create a class from a Dictionary in C#? [duplicate]

This question already has answers here:
How to dynamically create a class?
(15 answers)
Closed 3 years ago.
I have written a method which creates a Dictionary. I need to convert this dictionary to a class.
Example of Dictionary
Dictionary<string, dynamic> myDictionary = new Dictionary<string, dynamic> {
{ "ID1", 12 },
{ "ID2", "Text2"},
{ "ID3", "Text3" }
};
and this is the sample of the class which needs to be created:
public class Foo
{
public int ID1 { get; set; }
public string ID2 { get; set; }
public string ID3 { get; set; }
}
Your requirements are not clearly stated, but I'm guessing you are looking for a dymamic type that has properties whose names map to dictionary keys.
In that case you can use a simple dictionary wrapper like this one:
class DynamicDictionaryWrapper : DynamicObject
{
protected readonly Dictionary<string,object> _source;
public DynamicDictionaryWrapper(Dictionary<string,object> source)
{
_source = source;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
return (_source.TryGetValue(binder.Name, out result));
}
}
Which you can use this way:
public static void Main()
{
var myDictionary = new Dictionary<string, dynamic> {
{ "ID1", 12 },
{ "ID2", "Text2"},
{ "ID3", "Text3" }
};
dynamic myObject = new DynamicDictionaryWrapper(myDictionary);
Console.WriteLine(myObject.ID1);
Console.WriteLine(myObject.ID2);
Console.WriteLine(myObject.ID3);
}
Output:
12
Text2
Text3
Link to working example on DotNetFiddle
As other people mentioned, this situation is very usual and definitely requires a context to solve it from a better perspective, as I suspect a bad architecture of the code base. Nonetheless, your question remains valid. To solve it, you have at least two possibilities:
1. Require development time; negligible time at runtime - Simply create a function that maps a given dictionary to an instance of your class. Example:
Foo MapDictionaryToFoo(IReadOnlyDictionary<string, dynamic> d)
{
return new Foo
{
ID1 = d[nameof(Foo.ID1)],
ID2 = d[nameof(Foo.ID2)],
ID3 = d[nameof(Foo.ID3)]
};
}
Example of call:
Foo myFoo = MapDictionaryToFoo(myDictionary);
2. Require runtime time; negligible development time - Create a function that maps a given dictionary to an arbitrary class, typically using Reflection. The example below assumes your class has a default constructor, therefore acting as a factory as well. If this is not the case, an existing instance can be passed in an additional parameter:
T CreateFromDictionary<T>(IReadOnlyDictionary<string, dynamic> d) where T : new()
{
T obj = new T();
foreach (var propertyInfo in typeof(T).GetProperties())
{
propertyInfo.SetValue(obj, d[propertyInfo.Name]);
}
return obj;
}
Example of call:
Foo myFoo = CreateFromDictionary<Foo>(myDictionary);
If I have to pick one, I would choose the first approach, as I avoid any Reflection, that is time consuming at runtime.

Apply hashtable to object properties?

After an extensive search, I ask here: is there a way to "apply" a hashtable to object properties? For example, if I have a class:
public class MyClass
{
public string PropertyOne {get;set;}
public int PropertyTwo {get;set;}
}
Now, if I have a Hashtable of:
var table = new Hashtable {
{ "PropertyOne", "My string"},
{ "PropertyTwo", 4 }
};
Can I plug the table into an instance of the class so that Object.PropertyOne becomes "My string", etc, without having to parse it myself?
What you are referring to is often referred to as a mixture between "auto-conversion" and "de-serialization". In this specific case it is most easily achieved via non-recursive reflection.
MyClass mine = new MyClass();
table.Cast<DictionaryEntry>()
.ToList()
.ForEach((entry) => {
var field = mine.GetType().getProperty((string)entry.Key);
field.SetValue(mine, entry.Value);
});

How to initialize auto-property to not null in C#?

I have a property:
public Dictionary<string, string> MyProp { get; set; }
When I invoke that property to add an item, I get a NullReferenceException.
How would I do the null check in the property itself so it gives me a new one if it is null? While keeping in the auto-property pattern.
Without an explicit private variable the only other way would be to add some code to the constructor of the class:
MyProp = new Dictionary<string,string>();
You can initialize it in your constructor:
public MyClass()
{
MyProp = new Dictionary<string, string>();
}
I don't think you will want a setter, since that will always make a new dictionary, as others have pointed out by calling the setter in the constructor. A better approach is:
public Dictionary<string, string> MyProp { get; internal set; }
public MyClass() { MyProp = new Dictionary<string, string>(); }
Here you've used the internal setter to create the dictionary. After this, if you want to add an element to the dictionary, you would do this in your code:
InstanceOfMyClass.MyProp.Add(blah, blah);
where you use the getter to get the dictionary object, then do an Add to add a new item. You can't call the setter from your code and accidentally wipe out the dictionary, because it will look readonly to anything outside of MyClass.
For other people falling over this old question, there is a new feature in C# 6.0.
In C# 6.0, you can also initialize that property to some constant value in the same statement, like this:
public Dictionary<string, string> MyProp { get; set; } = new Dictionary<string, string>();
Initialize it in the constructor
public MyClass(){ dictionary = new
Dictionary<string,string>()
}
You will have to use an explicit backing field, you cannot change the getter or setter for auto-properties.
There's an attribute class named DefaultValueAttribute that allows you to specify the desired default value of a member, however, it doesn't automatically set the member to the value specified; hope is not lost, though, as you can use reflection to retrieve this value at runtime and apply it, as posed in this corner of the internet:
static public void ApplyDefaultValues(object self)
{
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(self))
{
DefaultValueAttribute attr = prop.Attributes[typeof(DefaultValueAttribute)] as DefaultValueAttribute;
if (attr == null) continue;
prop.SetValue(self, attr.Value);
}
}
I haven't tested this, and there may be issues with certain types but I'll leave it to your consideration and discretion. Should you decide to implement this then improvements could certainly be made.
If you were to run this code, you would get a NullReferenceException because the field is never initialized.
class Program
{
static void Main(string[] args)
{
Person sergio = new Person();
sergio.Items.Add("test", "test");
Console.ReadKey();
}
public class Person
{
public Dictionary<string, string> Items { get; set; }
}
}
So one way to solve this would be to initialize it, in the class´s constructor.
class Program
{
static void Main(string[] args)
{
Person sergio = new Person();
sergio.Items.Add("test", "test");
Console.ReadKey();
}
public class Person
{
public Dictionary<string, string> Items { get; set; }
public Person()
{
Items = new Dictionary<string, string>();
}
}
}

LINQ query code for complex merging of data

I've posted this before, but I worded it poorly. I'm trying again with a more well thought out structure.
I have the following code and I am trying to figure out the shorter linq expression to do it 'inline'. Please examine the "Run()" method near the bottom. I am attempting to understand how to join two dictionaries together based on a matching identifier in one of the objects - so that I can use the query in this sort of syntax.
var selected = from a in items.List()
// etc. etc.
select a;
so that I can define my structure in code like ...
TModelViewModel = new TModelViewModel
{
TDictionary = from a in items... etc. etc...
}
instead of going through a bunch of foreach loops, extra object declarations, etc.
This is my class structure. The Run() method is what I am trying to simplify. I basically need to do this conversion inline in a couple of places, and I wanted to simplify it a great deal so that I can define it more 'cleanly'.
class TModel
{
public Guid Id { get; set; }
}
class TModels : List<TModel>
{
}
class TValue
{
}
class TStorage
{
public Dictionary<Guid, TValue> Items { get; set; }
}
class TArranged
{
public Dictionary<TModel, TValue> Items { get; set; }
}
static class Repository
{
static public TItem Single<TItem, TCollection>(Predicate<TItem> expression)
{
return default(TItem); // access logic.
}
}
class Sample
{
public void Run()
{
TStorage tStorage = new TStorage();
// access tStorage logic here.
Dictionary<TModel, TValue> d = new Dictionary<TModel, TValue>();
foreach (KeyValuePair<Guid, TValue> kv in tStorage.Items)
{
d.Add(Repository.Single<TModel, TModels>(m => m.Id == kv.Key),kv.Value);
}
}
}
Haven't really tested this, and it's quite ugly, but I think this should work:
Dictionary<TModel, TValue> d = new Dictionary<TModel, TValue>();
d = d.Concat(tStorage
.Items
.Select(i => new KeyValuePair<TModel, TValue>(
new TModel { Id = i.Key }, i.Value))).ToDictionary(i => i.Key, i => i.Value);

Categories

Resources