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.
Related
Currently I am receiving an array of objects from a database.
object [] sqlResultData = DatabaseCall.Result();
This array of objects needs to be matched to class variables like this
CClassOfVars classVar = new CClassOfVars();
classVar.myProperty = sqlResultData[0];
classVar.myProperty1 = sqlResultData[1];
What i wish to do is pass the list of propertys on the class in order to a function and have the mapping from the object array occur automatically based on the order.
For example:
Method defined like this
FillData(object [] databaseValues, IList<object>())
Called like this
CClassOfVars classVar = new CClassOfVars();
object [] sqlResultData = DatabaseCall.Result();
FillData(sqlResultData, new List<object>(){classVar.myProperty,classVar.myProperty1});
The FillData function would hopefully type cast and set the values of myProperty and myProperty1 to the values in array locations of 0,1 etc...
Something like this
FillData(object [] databaseValues, IList<object> mapMe)
{
for (int i = 0; i < mapMe.Count; i++)
{
mapMe[i] = CastToTheCorrectType(mapMe[i], databaseValues[i]);
}
}
Cast to the correct type could look like this?? I took from here: cast object with a Type variable
public T CastToTheCorrectType<T>(T hackToInferNeededType, object givenObject) where T : class
{
return givenObject as T;
}
How can i pass a list of different object types to all have there values modified and assigned within a different function?
The matter you asking about is dark and difficult to be implemented through just a function. There are frameworks out there dealing with object relational mapping. If it is an option, install and learn some OR/M. If not ... well, there might be some dirty way.
You can use the JSON.NET library to do the heavy lifting for you. It's super easy to use and install through Nuget. My point is as follows.
Construct an anonymous object. Use the property names of the original object.
Fill it with the data from the object array. Spin a loop over the object array...
Serialize the anonymous object.
Deserialize the JSON string into the target type.
At this point, JSON.NET will handle property mapping for you.
List item
E.g. if your target type is Person you might do this:
var x = new
{
FirstName = String.Empty,
LastName = String.Empty
};
var persons = new List<Person>(sqlResultData.Length);
foreach (var record in sqlResultData)
{
x.FirstName = record[0];
x.LastName = record[1];
var s = JsonConvert.SerializeObject(x)`
var personX = JsonConvert.Deserialize<Person>(s);
persons.Add(person);
}
I'm using TweetInvi to grab a bunch of tweets that match a specified hashtag. I do this with the following:
var matchingTweets = Search.SearchTweets(hashtag);
This returns an IEnumerable (named ITweet, interface of Tweet), however I cannot create a List<> of Tweets, because Tweet is a static type.
I made, instead, a list of objects, using:
List<object> matches = matchingTweets.Cast<object>().ToList();
However, although each member of the matchingTweets IEnumerable has a number of properties, I cannot access them using:
long tweetID = matches[i].<property>;
Using matches[i].ToString() returns the tweet content, so how can I effectively cast the results in matchingTweets to a list, and subsequently access the properties of those list members? I would ideally like to avoid using dynamic.
In your example above you were trying to grab the ID from the tweet. ITweet implements ITweetIdentifier which contains the Id property. You can literally just access it by:
var matchingTweets = Search.SearchTweets(hashtag);
//Grab the first 5 tweets from the results.
var firstFiveTweets = matchingTweets.Take(5).ToList();
//if you only want the ids and not the entire object
var firstFiveTweetIds = matchingTweets.Take(5).Select(t => t.Id).ToList();
//Iterate through and do stuff
foreach (var tweet in matchingTweets)
{
//These are just examples of the properties accessible to you...
if(tweet.Favorited)
{
var text = tweet.FullText;
}
if(tweet.RetweetCount > 100)
{
//TODO: Handle popular tweets...
}
}
//Get item at specific index
matchingTweets.ElementAt(index);
I don't know exactly what you want to do with all the info, but since the SearchTweets returns a IEnumerable of ITweets you have access to anything an ITweet has defined.
I highly recommend looking through their wiki. It's pretty well organized and gives you clear examples of some basic tasks.
It makes sense you cannot access the properties. You cast it into object so you can only access the objects properties and methods (that like you said might have been overridden).
It should be fine to just access it like this:
List<ITweet> tweets = matchingTweets.Take(5).ToList();
What you can do is project it to a new object of yours:
var tweets = matchingTweets.Select(item => new {
property1 = item.property1,
property2 = item.property2
})
.Take(5).ToList();
Then you will be able to access what you need. Now, if you need to share this data outside the scope of that function create a DTO object and initialize it instead of the anonymous type.
Depending on the size of the project and amount of effort usually it is in any case a good practice to create a layer of DTO objects when you interact with an external service like this. Then if their models changed you can contain your changes only to the DTOs.
If all you want are the ids of the first 5 then:
var ids = matchingTweets.Take(5).Select(item => item.id).ToList();
I am assigning property names of a dynamic object as ints in string form. The int value represents an int ID in a database I am using. However I am stuck on how to retrieve the value assigned to the property as shown below:
dynamic test = new ExpandoObject()
IDictionary<string, object> proxyFiler = test as IDictionary<string, object>;
proxyFiler["four"] = 4;
proxyFiler["5"] = 5;
int r = test.four; // Works
int s = test.5; // Doesn't work
A method which reads the database will return an "int" and I would like to be able to access the property value with that property name.
To expand on this: what if I wanted to do a linq query to sort out a list of dynamic objects according to a property name? In this case I need to get the propertyName which I have retrieved as a string e.g. "15":
return disorderedList.OrderBy(o => o.propertyName).ToList();
Does anyone know a simple solution to this problem or do you recommend a different approach? Thanks.
In order for dynamic to work in this way, the key has to follow the rules for valid identifier names in C# (the rules are specified in this outdated MSDN page, but also in the C# language specification). A single number (5) is not an allowed identifier name, which is why that doesn't work.
Note that you can still retrieve the value by using the type as a dictionary, in a similar manner to how you populated it.
As for your second example - you are never using value, so it has no effect. It's the same as just writing int r = test.four;
Edit:
I believe, given your approach, you'd need to cast to a dictionary:
return disorderedList
.OrderBy(o => ((IDictionary<string, object>)o)[propertyName]).ToList();
I have a method, which takes data received from database, and it takes only data which has a specific day:
private static **return type** FilterDataByDay(DataTable dt, string nameOfTheDay)
{
var data = dt.AsEnumerable().Select(x => new
{
code = x.Field<string>("Code"),
day= x.Field<string>("Day"),
name= x.Field<string>("Name"),
startTime= x.Field<int>("StartTime"),
endTime= x.Field<int>("EndTime")
})
.Where(x => x.day.Equals(nameOfTheDay))
.ToList();
return data ;
}
The problem is I don't know how to return data from this method, that other method could take it ant print it out, every element like of each row, it should let me print something like:
foreach(var variable in "the retuned data from method")
{
Console.WriteLine(variable.code +" "+ variable.day + ..etc...
}
The thing about anonymous types is that they're not named, e.g. anonymous.
The best course of action is to define your own class with the appropriate properties after which you can return IEnumerable<SomeClass>.
You could create a Wrapper class and then you'll have IEnumerable<MyClass>
or you can use IEnumerable<dynamic> , but this way - you wont have intellisence.
Defining a proper class that would encapsulate the loaded data is probably the best way to go. But if you are dealing with data you will not need later and you don't pass them to much around, you can leverage the Tuple class. It will look slightly awkward, but if it is just your code and it is not a part of a public API then it is also usable.
Your return type would then be IEnumerable<Tuple<string, string, string, int, int>>
I am trying to setup a WPF datagrid. The standard datagrid is setup to accept a list of objects which are displayed on different rows, with a column for each property. I actually need to do the inverse; a row for each property, and a column for each object in the list. Therefore I started with the solution proposed by blindmeis here in order to handle a dynamic number of columns and it works well so far.
I have a class DataGridVM to which I can pass a list of objects. Each of the objects has its own View Model which derives from a class ParentalBaseVM. Each property of that object has its own View Model which derives from a class ElementVM.
Each ParentalBaseVM can return list of ElementVM for each of its object’s properties through overriding the virtual method PropertyLists
E.g. within an example of a class dervived from ParentalBaseVM I have:
public override Dictionary<string, List<ElementVM>> PropertyLists
{
get
{
Dictionary<string, List<ElementVM>> iPropertyLists = new Dictionary<string, List<ElementVM>>();
List<ElementVM> BasicProperties = new List<ElementVM>();
BasicProperties.Add(iNBViewModel);
BasicProperties.Add(iIDViewModel);
iPropertyLists.Add("Basic", BasicProperties);
List<ElementVM> AdvancedProperties = new List<ElementVM>();
AdvancedProperties.Add(iNBViewModel);
AdvancedProperties.Add(iIDViewModel);
AdvancedProperties.Add(iXSAreaViewModel);
iPropertyLists.Add("Advanced", AdvancedProperties);
return iPropertyLists;
}
set
{
}
}
As you can see, I can return a different set of properties by passing either “Basic” or “Advanced” as a string.
The DataGridVM code is below. I pass to this the list of objects (columnList) and the string which represents the (“Basic” or “Advanced” in the example above)
class DataGridVM
{
private List<List<ElementVM>> iDataList;
public DataGridVM(List<ParentalBaseVM> columnList, string rowListKey)
{
iDataList = new List<List<ElementVM>>();
for (int i = 0; i < columnList[0].PropertyLists[rowListKey].Count; i++)
{
List<ElementVM> newRowList = new List<ElementVM>();
for (int j = 0; j < columnList.Count; j++)
{
newRowList.Add(columnList[j].PropertyLists[rowListKey][i]);
}
iDataList.Add(newRowList);
}
}
public List<List<ElementVM>> DataList
{
get
{
return iDataList;
}
set
{
}
}
}
Finally, the datagrid is populated using:
testControlDataGrid.testDataGrid.ItemsSource = testDataGridVM.DataList;
And then the columns are generated dynamically (the code within CreateDataTemplate sets up the bindings)
for (int i = 0; i < testDataGridVM.DataList[0].Count; i++)
{
testControlDataGrid.testDataGrid.Columns.Add(new DataGridTemplateColumn()
{
Header = "Col" + i,
CellTemplate = CreateDataTemplate(TheTextBlock.GetType(),i)
});
}
This all works fine, but it feels very messy. Passing string values like “Basic” and accessing dictionaries feels wrong. Perhaps there is an elegant solution where I have classes deriving from DataGridVM such as DataGridVMBasicProperties which accesses the “Basic” properties of the object, but I’m not sure if this would result in repeating lots and lots of code.
Also, I’m not sure cluttering up the ParentalBaseVM class with a method which returns the list of properties is great either. I was thinking of perhaps moving this to a new base class PropertiesListGenerator which can simply have a ParentalBaseVM passed to it, and returns a list of ElementVM. A derivation could be BasicPropertiesListGenerator, and a further derivation of this could be AdvancedPropertiesListGenerator. However, if not all ParentalBaseVM contain an "advanced" list and only the "basic" list then this may cause problems. My main aim here is to avoid repeating lots of code.
I have never used Delegates or Interfaces enough to truly understand them, so my coding skills aren’t really firing on all cylinders. Maybe they can help provide an elegant solution?
Any help is appreciated. I’m new to this and programming isn’t my full time job (evidently). If you see room for improvement in layout, readability, convention following, please feel free to suggest, I certainly will not be offended.