I am looking for an easiest way to assign values to the properties of a class dynamically.
In my WPF App, I have a list header values as shown below :
Name Mark Class --> header values (Name, Mark, Class these are the 3 headers)
---- --- -----
Nick 10 5
Tom 12 7
John 09 4
Sometimes, the header values changes:
Name Mark Percent Phone --> 4 header values
---- ----- ------- -----
So we cannot predict the number of headers. Sometimes it will be 5, sometimes it will be 2,
sometimes the number of headers will be 6, etc
So I created a class Named StudentMark with following properties.
public class StudentMark
{
[Order]
public double? Col1 {get;set;}
[Order]
public double? Col2 {get;set;}
[Order]
public double? Col3 {get;set;}
- - - - -
[Order]
public double? Col10 {get;set;}
}
When I get the list from server, I assign the values to the properties of the student mark class are shown as below code. This is doing for plotting a graph. We don't know the column header values in advance, we do like these.
StudentMark sm = new StudentMark();
var properties = from property in typeof(StudentMark).GetProperties()
where Attribute.IsDefined(property, typeof(OrderAttribute))
orderby ((OrderAttribute)property.GetCustomAttributes(typeof(OrderAttribute), false).Single()).Order
select property;
//PropertyInfo[] properties = typeof(StudentMark).GetProperties();
foreach (string str in HeaderColumns)
{
var d1 = csv.GetField<string>(str); // taking cell value
foreach (PropertyInfo property in properties)
{
if (property.PropertyType == typeof(Double?))
{
if (property.GetValue(sm) == null)
{
property.SetValue(sm, d1);
break;
}
}
}
}
this is working but very very very slow. Is there anyway to do it without using reflection ??
Try to keep typed data separate from arbitrary untyped data. So if you want to represent a table of arbitrary user defined data you would do it something like:
public class MyTable{
public List<string> Headers {get;}
public List<List<string>> Rows {get;}
}
If the only thing you will be doing is presenting it to the user, and reading writing csv-files, such an representation is perfectly appropriate.
It is only when you need to use the data for something you need to use actual types to represent the data. But this can be quite complicated and would involve a lot of data validation to ensure the data is on the correct format.
You could for example have logic to check if each header has some specific value, and then parse the values for each row to a set of predefined types. If either the headers have incorrect values, or the parsing of some value fails, you would give an error and let the user deal with the problem.
If you want minimize the risk of mistakes, you should make them impossible in the first place, or detect them as early as possible, i.e. enforce the correct header names, parse values as soon as they are entered etc.
If you need to combine typed data with untyped data you could for example use a dictionary:
public class MyDataRow{
public string name {get;}
public int Mark {get;}
public Dictionary<string, string> UserDefinedData {get;}
The user defined data would just be treated as an opaque data blob, tracked thru the system, but not used for any computation, or if it is, with a great deal of error checking.
Related
I have 12 columns in a datagridview (they're 12 properties going from v1 - v12). Is it possible to create a dynamic system that does something like this:
int i = 5;
var variablename = "v" + i;
String content = product.variablename;
This would be a generic function of
if(i == 5) {
content = product.v5
}
Yes, I know that naming my properties v1-v12 isn't good practice, but it has its uses. I could write 12 if clauses, but I'm just wondering if it's possible or not.
EDIT:
In the specific example I have an array of 8000 products with each v1-v12 properties. I want to dynamically get the values of specific cells, so
product[row].(v+column) should become products[23].v5 for example.
It's more of an example case than it is actually needed, just want to figure out if it can be done.
Dictionary will give you flexibility and control to store as many as you like and retrieve them without using Reflection etc.
var values = new Dictionary<string, string>();
values.Add("v" + i, "somevalue");
and to retrieve it:
var storedValue = values["v" + i];
On a side note, if you are using Data Grid View to have multiple lines. You can also use DataTable to store information. Or if you have a fixed structure, why not make a class that will represent that information and use List<T>
var variablename = "v" + i;
MethodInfo method = product.GetType().GetMethod(variablename);
object result = method.Invoke(product, new object[] {}); // pass in the parameters if you need to
You can use reflection for that purpose
So you have a class Product that has 12 properties that got no Usefull name?
In that case i would just create a class Product that has an Array of Properties.
public class Product
{
public string[] Properties {get;set;}
}
Then to access the 5t generic nameless property of the product 23 you call.
products[23].Properties[5]
While I still doubt that the products properties can not be named properly.
Background:
I'm building a system to assign academic advisors to university students based on the student's attributes and advisor's acceptance. Now I want to check to see if every possible student can be assigned an advisor before I start processing students and committing changes to our CRM and Active Directory. There are about 15,000 records, so I don't want to commit changes unless all students have an advisor.
My current system has an 'AdvisorGroup' object to hold a list of 'AdvisorRules.' My 'AdvisorRules' object is populated from CRM:
class AdvisorRule
{
public AdvisorCondition Condition { get; set; }
public AdvisorField Field { get; set; }
public String Value { get; set; }
}
AdvisorCondition can be LessThanEqual, GreaterThanEqual, or Equal. AdivsorField can be Credit(how many credits each advisor will accept), international(if the advisor accepts intentional students), honors(if the advisor accepts honors students or not) and lastName(last names the advisor will accept.)
'Value' is the target that is compared to 'AdvisorField.' For example the list of AdvisorRules in an AdvisorGroup could hold the following rules:
AdvisorCondition = "Equal" AdvisorField = "International" Value = No
AdvisorCondition = "Equal" AdvisorField = "honors" Value = No
AdvisorCondition = "LessThanEqual" AdvisorField = "Credit" Value = 89
AdvisorCondition = "Equal" AdvisorField = "LastName" Value = A
AdvisorCondition = "Equal" AdvisorField = "LastName" Value = B
This advisor would accept a student with a last name starting with A or B, with less than 89 credits, and is not an international or honors student.
Question:
Is there a way to check to make sure every possible student will be assigned an advisor before I start processing? I'm trying not to be extremely explicit in my coding. I was thinking something like this, but would be open to redesigning if I can find a better way:
private bool checkRuleCoverage()
{
//somehow generate list of possible scenarios here
foreach (possible scenario in list of possible scenarios)
{
bool covered = isCovered(possible scenario);
if(!covered) {throw error and return}
}
}
private bool isCovered(List<AdvisorGroup> adGroups, possibleScenario ps)
{
foreach (AdvisorGroup advisor in adGroups)
{
foreach (AdvisorRule rule in advisor.rules)
{
if(advisor.rules == ps)
return true;
}
}
return false;
}
If you have all of your student records in a database, then the solution would be to use set logic with appropriate indexing to get the answer. For example, you could code your own solution such that you sort the student body along each of the possible values that an advisor rule applies to.
Then, without iterating (though you've already iterated in order to sort) you can find all of the students below x or over y on a certain train, and then compare that to the students outside of the range on another stat and so on. Any student outside of the range on all stats like Mao47's comment suggest would be un-advisable.
Of course, in the time it took you to code this in C# you could have just iterated over the advisor rules and found the values of the ranges and applied this to a where clause in a select on SQLServer or MySQL or any DB that's set-based.
Of course, this rough check misses out on the possibility of partial rule-sets, where a student is outside of the range of all but 1 advisor rule, and then that 1 rule is not enough because the advisors also have other requirements. In order to solve that, you will have to have multiple advisor-rule-set-ranges, or rather, you will iterate over all advisor-rules in the worst case. Doing this in the DB will probably still be ok, as long as the student's scores on the rules-properties are properly indexed.
I have a scenario where I need to use tabular data which is unlikely to change but which helps implement business logic:
Table
Parent Child Relationship Allowed
A B C True
B A C False
Each row represent a business rule. Based on this table I need to populate a dropdown control with the contents of the "Relationship" column. Can I have some sort of data structure within C# to store this tabular data, or do I need to use a a database table?
Unless you need to persist this data across sessions, you don't need to store it in a database table. From the perspective of Object Oriented design, why not make an object, and therefore class, that represents the structure you need. Something like this:
public class Relationship
{
public string Name { get; set; }
public string Parent { get; set; }
public string Child { get; set; }
public bool Allowed { get; set; }
}
Note of course that I'm using strings where you might want to use further objects of their own 'type'. Additionally, keep in mind access, and what should and shouldn't be allowed to access these properties... This is example is intentionally simple at this point!
I would agree that a full blown database may be overkill if this is all the data you need to store, so you could theoretically hardcode the data and structure in C# if you really wanted to, but not a good idea in almost all cases - even if it is unlikely to change.
At a minimum store the data in a little XML / config file so that IF it does change, you do not need to recompile the application.
Use DataTable: http://msdn.microsoft.com/en-us/library/System.Data.DataTable.aspx
You can create your Table and fill it like this:
// Definition
DataTable table = new DataTable();
DataColumn column = new DataColumn("Parent", typeof(string));
table.Columns.Add(column);
// Data
DataRow row = table.NewRow();
row["Parent"] = "A";
table.Rows.Add(row);
public interface IRule
{
bool Check(string input);
}
I have an interface that defines a rule. A rule is just a generic business rule or constraint that a user can create. So I have two sample rules:
public class ContainsRule : IRule
{
public string MustContain { get; set; }
public bool Check(string input)
{
return input.Contains(this.MustContain);
}
}
public class LengthRule : IRule
{
public int MaxLength { get; set; }
public bool Check(string input)
{
return input.Length <= this.MaxLength;
}
}
Rules may have more than one property that can be set, but in this example, each of these rules only have one property.
A user can create their own set of rules that should be saved. For example, a user have these three rules:
IRule[] rules = new IRule[]
{
new ContainsRule { MustContain = "foo" },
new ContainsRule { MustContain = "bar" },
new LengthRule { MaxLength = 5}
};
I need to persist this information to a database or some data store for each user. Since each user can have their own set of rules, I'm not sure what the database tables should look like.
User | ClassName | Parameters
-----------------------------------------------
1 | Namespace.ContainsRule | MustContain:foo
1 | Namespace.ContainsRule | MustContain:bar
1 | Namespace.LengthRule | MaxLength:5
My initial guess would be to create a table that looks something like the above, where parameters should a string. This means I would need to parse out the information and use reflection or something to set the properties. I would need to use the activator to create the class using the ClassName column. Another suggestion was instead of creating a delimited string for all the properties, there would be another table. Each of the properties would be its own row that has a foreign key relationship back to a row in the table above.
However, both examples don't seem to be the best way of saving these rules. Is there a better way to do this?
Why not use XML serialisation. The database table would contain the User # and the XML serialisation of the indvidual rule.
I believe that you are retrieving from database.
If so, try my suggestion.
Store the retrieved data into datatable, or convert them to datatable before applying the rule.
So the rule can be put as normal sql in datatable's filter property.
Instead of rule name and parameters, you can change it to a column containing
column like '%foo%'
Then apply this on the datatable's filter.
PS: I have converted List to Datatable and used such filter before
It seems to me, simply put, you need to map your objects to SQL tables (if only there was a technology that could to do this automatically... :)
Based on what you have posted, I envisage at least six SQL tables, more if there are further subclasses of rule e.g.
Rules
MustContainTextRules (subclass of Rules, 1:0..m)
MaxLengthRules (subclass of Rules, 1:0..1)
[Possibily further subclasses of Rules e.g. MinLengthRules?]
Rulesets ("a set of Rules")
Users
RulesetOwnership (relationship table between Users and Rulesets)
Whether they are distinct tables may be influenced by whether the rules are interrelated e.g. if the MinLengthRule value for a Ruleset cannot exceed its MaxLengthRule value then you may find it difficult to write a SQL constraint to validate this when they are in different tables.
Imagine I have a C# app sitting on a server somewhere that is creating instances of the Item class and publishing them on a messaging service.
class Item
{
public int ID1, ID2, ID3;
public double Value1, Value2, Value3;
}
Now I have another C# app on a desktop somewhere listening to these messages. I want to be able to create callbacks based on specified values of the ID# fields. For example, "call this method whenever a message comes in where ID1 = 2, ID2 = 160, and ID3 = anything". I think this would be straightforward if I used string key-value pairs, but ideally I could do this without giving up static typing. I imagine this requires reflection, but I'm not entirely sure where to start.
I'm picturing the app creating an instance of Item with the required ID# values (let's say -1 means unspecified), and passing that into a RegisterCallback method of some object ItemListener. Then whenever ItemListener receives a new Item message, it can check for any callbacks that match, and act accordingly. Is this a reasonable design? Any suggestions on what to look at to implement it?
class ConditionalCallback()
{
public Predicte<Item> Predicate {get; set;}
public Action<Item> Callback {get; set;}
}
List<ConditionalCallback> callbacks = new List<ConditionalCallback>();
public AddCallBack(Predicte<Item> pred, Action<Item> callback)
{
callbacks.Add(new ConditionalCallback {
Predicate = pred,
Callback = callback
});
}
void HandleItem(Item item)
{
foreach(var cc in callbacks)
if (cc.Predicate(item))
cc.Callback(item);
}
//
AddCallBack( i=> i.ID1 = 2 && i.ID2 = 160 && i.ID3 = anything", MyCallback);
It's possible to do without giving up type safety. What you basically need is a tuple type (.NET 4.0 has this, but if you are not using that, you can create your own easily) where the members are nullable types of the id types that you want to match on.
You would then use instances of these types as keys in a dictionary where the value is the delegate that you would execute on a match. For example, your key type would look like this:
struct ItemKey
{
public int? ID1, ID2, ID3;
public double? Value1, Value2, Value3;
}
Then, for your example of processing a message where ID1 = 1, ID2 = 160, and ID3 = anything, you would instantiate the key for the delegate in the dictionary like this:
new ItemKey { ID1 = 1, ID2 = 160 }
Note, it's very important here that ItemKey is a structure, as it provides the correct implementations of GetHashCode and Equals which are essential to being keyed in the dictionary correctly.
A drawback of this design is that you have to be explicit for all the kinds of partial matches that are possible.
For example, if you wanted a delegate to be processed when the ID1 = 2, and another one where you want to process when ID1 = 2 and ID2 = 3, you have to specify those cases specifically. This can cause the dictionary to grow very very fast if you have many permutations.
If this is the case, you might want to look into a database solution of some kind where you store the ID values in separate columns, and then do a lookup on the appropriate columns (filtering on selective columns). Then, you would have a type name in a field on the row, which you could use to create a type instance through reflection, which implements an interface or derives from a base type, which you can create a variable of and call the method which performs the functionality.