I've read few posts, and I'm still having troubles with adding properties to a class in runtime. It should be simple, because I have a class like this:
public class MyClass
{
String Template;
String Term;
}
During runtime, I have to add few attributes, like Phone, Email (it depends...).
Could someone please explain me how to add these properties during class initialization?
Srecko
I don't think adding a property is the right thing to do here.
The attributes like "Email" or "Phone" are just some additional pairs of a key and a value. You could use a Dictionary, but that would prevent you from using a key more than once (more than one email address for a contact for example). So you could just as well use a List<KeyValuePair<string, string>>. Like that:
public class MyClass
{
String Template;
String Term;
public List<KeyValuePair<string, string>> Attributes { get; private set; }
public MyClass() {
Attributes = new List<KeyValuePair<string, string>();
}
public void AddAttribute(string key, string value) {
Attributes.Add(new KeyValuePair<string, string>(key, value));
}
}
// to be used like this:
MyClass instance = new MyClass();
instance.AddAttribute("Email", "test#example.com");
instance.AddAttribute("Phone", "555-1234");
If you have c# 4.0 you can use the Expando object.
for earlier versions of c#, the generally accepted way of doing this is to create a "property bag" i.e. a collection (or dictionary) of key value pairs
dynamic foo = new ExpandoObject();
foo.Bar = "test";
you could add an dictionary with for your Key/Value-Pairs.
Then if you add your attributes you just add Key = Attributename, Value = YourValue to the dictionary.
Reading is as easy - just get the Value to the Key = Attributename from your dictionary.
Related
Basically i want to export some lists. Theese lists contains different columns. For example
StudentID - StudentName - Assignment1 - Assignment2 - Final Exam
But sometimes there are different exams. I am using tuple class to add theese lists.
exportList.Add(new Tuple<string, string, string>(item.ID, item.Name + item.Surname, payList[i]));
this contains 3 columns. Is there a way to change tuple parameters dynamically?
In your case i would not use Tuples. I rather would use classes, which inherit from one another, to allow variating properties.
For example:
public class Student // only a sample
{
public string Name
{
get;
set;
}
}
public class StudentWithGrade : Student
{
public int Grade
{
get;
set;
}
}
Your list could than accept types of Student, which can be a Student or StudenWithGrade or anything that inherit from student.
This makes your code also more readable for others.
EDIT
If you really need some thing dynamic, use a list of dictionaries,
where one entry in the list represents a kind of row and the entries
in the Dictionary<string, object> represents the columns.
No, tuples are immutable. It seems like you're not using tuples to what they're meant to be used.
If you insist in not using classes to hold your data, your best bet are dictionaries:
exportList.Add(new Dictionary<string, string>() { { "ID", item.ID }, { "Name", item.Name }, { "Surname", item.Surname }, { "PayList", payList[i] } });
Now if you get the whole item, you'll be able to edit each item as follows:
exportList[0]["ID"] = 11;
exportList[0]["Name"] = "Matías";
exportList[0]["Surname"] = "Fidemraizer";
Another option is using a dynamic object like ExpandoObject:
dynamic person = new ExpandoObject();
person.ID = 11;
person.Name = "Matías";
person.Surname = "Fidemraizer";
exportList.Add(person);
Since ExpandoObject implements IDictionary<string, object>, you can access properties using regular dot syntax, or you can cast an ExpandoObject to IDictionary<string, object> and access properties as dictionary keys:
dynamic person = exportList[0];
string name = person.Name;
// or...
IDictionary<string, object> person = (IDictionary<string, object>)exportList[0];
string name = (string)person["Name"];
BTW, I still feel that you should go with designing and using an actual class to hold your persons' data either way...
I've a problem with updating a dictionary
I also have read many topics about this saying all the same (e.g. Link)
ExampleDict[key] = value;
I was trying this to my own code:
Model:
public Dictionary<int, string> Info { get; set; }
public Dictionary<int, string> GetInfo(int id)
{
Info = new Dictionary<int, string>();
var game = db.Games.Find(id);
var playerOne = db.Players.Find(game.PlayerOneId);
var playerTwo = db.Players.Find(game.PlayerTwoId);
var PlayerOneName = playerOne.Nickname;
var PlayerTwoName = playerTwo.Nickname;
int scoreOne = CountScorePlayerOne();
int scoreTwo = CountScorePlayerTwo();
// old aproach:
Info.Add(scoreOne, PlayerOneName);
Info.Add(scoreTwo, PlayerTwoName);
//new approach
Info[key] = scoreOne;
return Info;
}
Error
The name 'key' does not exist in the current context
Note: I'm a student and this is for a school project.
Any ideas on what I am doing wrong?
Solved through the code sample from Jon Senchyna, Thank you!
It appears that you are never declaring the variable key. You probably did not mean to use "key" in the "new approach" line.
In addition, I believe your Dictionary is backwards, as it looks like the player name should be the key, not their score. The way you are currently declaring it (Dictionary<int, string>), you are creating a dictionary whose keys are int (score?) and whose values are string (name?).
Here are my suggested edits:
// Corrected dictionary definitions
public Dictionary<string, int> Info { get; set; }
public Dictionary<string, int> GetInfo(int id)
{
// You may want to use a local variable here instead
Info = new Dictionary<string, int>();
...
Info[PlayerOneName] = scoreOne;
Info[PlayerTwoName] = scoreTwo;
return Info;
}
Here are some useful links for learning more about using the Dictionary class (and C# in general if you browse around a bit):
MSDN
DotNetPearls
In the example link in your question there's the method:
public static void SafeDictionaryAdd(Dictionary<string, object> dict, string key, object view)
Which has a string key as an argument. You need to define that key, too.
I am in need of creating a dynamically extend-able class in C#.
The goal is to create a class what can contain all info from a given contact from an Android SQLite Contacts table. The table's structure is kinda weird, as it does not have set field names, but uses colums of 'field name' and 'field content'.
That's what I want to turn into a usable format where the code reads the database, and for each entry creates the matching sub-variable. Such I want to know the best method to do so (I guess a simple
{
this.(variableNames[i].ToString()) = variableContent[i];
}
will not do it), what is the least resource-eating, but fastest (and easiest) way.
And also if we are here, is there ANY method to call a type's (let's say, I create a new Contact with e-mail, workplace, name, and image tags, but these variables names' are unknown) ALL sub-variables (Contact.image, Contact.FirstName, Contact.Email, etc) dynamically?
Of course there will be standardized fields what should be in ALL contact (one of the three names, phone number, e-mail #work and #home, and such), but these should be called dynamically too.
Use a Dictionary<string,string> instead.
Dictionary<string,string> contactInfo = new Dictionary<string,string>();
public void ImportContact()
{
...
// for each fieldName and fieldValue from your table
contactInfo.Add(fieldName, fieldValue);
...
// check that all standard fields are present, if desired
}
public string FirstName
{
get { return contactInfo["FirstName"]; }
}
If you are willing to go with dynamic typing, you can use the dynamic type in C# 4. You can use ExpandoObject or DynamicObject as a base for your Contact types.
Here is an example of a Contact class that can work both statically typed with some pre-defined properties; and can have properties attached to it at run-time. When treating it statically, you can still get the values by using the indexer:
class Contact : DynamicObject
{
private readonly Dictionary<string, object> bag = new Dictionary<string, object>();
public string FirstName { get; set; }
public string LastName { get; set; }
public object this[string key]
{
get { return bag[key]; }
set { bag[key] = value; }
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (bag.ContainsKey(binder.Name))
{
result = bag[binder.Name];
return true;
}
return base.TryGetMember(binder, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
bag[binder.Name] = value;
return true;
}
}
Which you can then use like this:
// Contact is statically typed.
Contact c = new Contact();
c.FirstName = "test";
// Treat as dynamic and attach some extra properties:
dynamic dynContact = c;
dynContact.AddressOne = "Somewhere";
dynContact.AddressTwo = "Someplace else";
Console.WriteLine(dynContact.AddressOne);
Console.WriteLine(dynContact.AddressTwo);
Other than using dynamic, you cannot create a new class with dynamically typed properties. After all, how would you consume those properties ? You might be better off creating a class containing the properties that you must have; and put the rest in a Dictionary<string,object>.
If you're using .NET 4.0, there's dynamic support. You can create objects something like this:
var newContact = new object { FirstName = "name", LastName = "name", etc... };
Alternatively, you might want to try using a Dictionary.
I am using a Dynamic dictionary in C#. The problem I am facing is the behavior of TryGetMember which I am overriding in the dynamic dictionary class.
Here's the code of dynamic dictionary.
class DynamicDictionary<TValue> : DynamicObject
{
private IDictionary<string, TValue> m_dictionary;
public DynamicDictionary(IDictionary<string, TValue> a_dictionary)
{
m_dictionary = a_dictionary;
}
public override bool TryGetMember(GetMemberBinder a_binder, out object a_result)
{
bool returnValue = false;
var key = a_binder.Name;
if (m_dictionary.ContainsKey(key))
{
a_result = m_dictionary[key];
returnValue = true;
}
else
a_result = null;
return returnValue;
}
}
Here, TryGetMember will be called at runtime whenever we refer some key from outside, but it's strange that binder's Name member which always gives the key what we refer from outside, it always resolves the key name written as characters of alphabets.
e.g. if the object of DynamicDictionary made as:
Dictionary<string,List<String>> dictionaryOfStringVsListOfStrings;
//here listOfStrings some strings list already populated with strings
dictionaryOfStringVsListOfStrings.Add("Test", listOfStrings);
dynamic dynamicDictionary_01 = new
DynamicDictionary<List<String>(dictionaryOfStringVsListOfStrings);
string somekey = "Test";
//will be resolve at runtime
List<String> listOfStringsAsValue = dynamicDictionary_01.somekey
Now what happens here is "somekey" will become the value of a_binder (i.e a_binder.Name="somekey"). It should be resolved as a_binder.Name = "Test" and then from the dynamic dictionary it will locate listOfStrings against this key (i.e. actually "Test" but it resolves not the value but actual variable name as key).
Is there a way around this?
The point of dynamic typing is to make the member names themselves get resolved from the source code member access.
Dynamic typing is working exactly as it's meant to here - it's not designed to retrieve the value of the variable and use that as the member name - it's designed to use the member name you used in your source code (i.e. "somekey").
It sounds like you really don't need dynamic typing at all here - just use Dictionary<string,List<String>> as normal:
List<String> listOfStringsAsValue = dictionary[somekey];
EDIT: It sounds like you actually want to encapsulate a dictionary like this:
public class Foo // TODO: Come up with an appropriate name :)
{
private readonly Dictionary<string, List<string>> dictionary =
new Dictionary<string, List<string>>();
public List<string> this[string key]
{
get
{
List<string> list;
if (!dictionary.TryGetValue(key, out list))
{
list = new List<string>();
dictionary[key] = list;
}
return list;
}
}
}
Then you can do:
foo["first"].Add("value 1");
foo["second"].Add("value 2")
foo["first"].Add("value 1.1");
If you want to be able to attempt to fetch a list without creating a new one if it doesn't exist, you could add a method to do that.
It really doesn't sound like you need DynamicObject here.
I have a employee object as shown below
class emp
{
public int EmpID { get; set; }
public string EmpName { get; set; }
public int deptID { get; set; }
}
I need to create a mapping either in this class or a different class to map the properties with column name of my SQL
for eg. EmpdID="employeeID"
EmpName="EmployeeName"
deptID="DepartmentID"
When from my asp.net page when I create the employee class and pass it to a function:
for eg: emp e=new emp();
e.EmpID=1;
e.EmpName="tommy";
e.deptID=10;
When the emp object is populated and passed to the buildValues function it should return array of ComumnName(e.g.employeeID):Value(e.g.1),EmployeeName:tommy,DepartmentID:10)
string[] values=buildValues(emp);
public string[] buildValues(emp e)
{
string[] values=null;
return values;
}
I have 2 questions:
1. Where do I specify the mappings
2. How do I use the mappings in my buildValues function shown above and build the values string array.
I would really appreciate if you can help me with this
You need to use Reflection.
Specifically, you need to loop over typeof(Employee).GetProperties().
This is a solved problem. Do some research on ORM's and have a look at this SO question: .Net ORM that works well with MySQL
First of all, (as it was already said) it's best to leave this kind of mappings to an ORM tool, and just forget about them. However, ORM tools tend to be too "maternal" in protecting you from the gory details of data access and such, so it can be complicated to extend them, or change their behaviour.
That said, you could create a special class (Mappings) that would hold all mapping code. The mappings themselves are best kept in a dictionary, something like this:
static class Mappings
{
private static Dictionary<Type, Dictionary<string, string>> TypeMappings;
private static Dictionary<string, string> EmployeeMapping;
//... other mapped classes
static Mappings()
{
TypeMappings = new Dictionary<Type, Dictionary<string, string>>();
EmployeeMapping = new Dictionary<string, string>();
EmployeeMapping.Add("EmpID", "EmployeeID");
EmployeeMapping.Add("EmpName", "EmployeeName");
EmployeeMapping.Add("DeptID", "DepartmentID");
TypeMappings.Add(typeof(Employee),EmployeeMapping);
//... other mapped classes
}
public static string[] BuildValues<T>(T item)
{
if (!TypeMappings.ContainsKey(typeof(T)))
throw new Exception("wrong call");
Dictionary<string, string> mapping = TypeMappings[typeof(T)];
List<string> results = new List<string>();
foreach (var keyValuePair in mapping)
{
string propName = keyValuePair.Key;
string dbName = keyValuePair.Value;
PropertyInfo pi = typeof(T).GetProperty(propName);
object propValue = pi.GetValue(item, null);
results.Add(string.Format("{0}:{1}", dbName, propValue));
}
return results.ToArray();
}
}
Here, the TypeMappings is a dictionary of all mapped classes, whose mappings in turn are in propertyName - databaseName dictionaries.
The BuildValues method, takes those names, reflects the values, and build a results string.