I'm a bit new to C# and I got this script that gets a record from a mssql database. There it converts the key to an object.
Its:
Object obj = result[i];
When I enable a breakpoint on the line after the declaration I see the data that is inside the object. Now I need to access the attribute with the data but because Im a bit new to C# I dont know how to do that.
Lets say the attribute is called: name
I made a new class of my own also with the attribute name.
When I try to get the name of the key to my object with:
myObject.Name = (string) obj.Name;
The IDE already gives an error that the attribute in the obj isnt available.
How can I access the name attribute of the object to get it to my own object?
Thanks!
So result[i] is an instance of your class (which I'll call Foo for convenience)? Then you can say
Foo obj = result[i];
myObject.Name = obj.Name;
or
Object obj = result[i];
myObject.Name = ((Foo)obj).Name;
You need to cast your object to proper type. E.g. if your object is:
class MyObject
{
public string Name { get; set; }
}
than you need to cast it like:
MyObject obj = (MyObject)result[i];
you're trying to access an attribute of the Object class, and it has no attributes. You either have to cast your obj to the class that you created, the one that has the Name attribute, or (more simply), when reading the database read it directly into an instance of your class, something like:
MyClass obj = result[i]
What data is present in result[i]? Is it just a string from a field in the record in the database? (That is, is result a DataRow?) As it stands, you're placing it inside of just an Object which doesn't know much about it. Basically, you're "boxing" it and removing knowledge of the object's data from the compiler.
If result[i] is just a string, try something like:
myObject.Name = System.Convert.ToString(result[i]);
Now, this is fairly beginner in that there are other considerations to be made here. If result[i] is ever null then this will throw an exception, etc. But while you're learning this should get the data you're looking for.
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);
}
So I have 2 classes, both have identical Property names. One class contains different variables: int, strings, bool and DateTime The second class contains only 1 int and the rest are all strings.
Now I want to loop through all the properties, get the value from class1, encrypt that data and save it as a string in obj2, then return it to the main form (to save it in a database later).
public PersoonEncrypted EncryptPersonClass(Class1 object1)
{
PersoonEncrypted persEncrypt = new PersoonEncrypted(); //second class obj
Type type = object1.GetType();
PropertyInfo[] properties = type.GetProperties();
Type type2 = persEncrypt.GetType();
PropertyInfo[] properties2 = type.GetProperties();
foreach (var bothProperties in properties.Zip(properties2, (obj1, obj2) => new { Obj1 = obj1, Obj2 = obj2 }))
{
string value = "";
value = bothProperties.Obj1.GetValue(object1) as string;
if (!string.IsNullOrWhiteSpace(value))
{
string encryptValue = Encrypt(value);
if ((bothProperties.Obj2 != null) && (bothProperties.Obj2.PropertyType == typeof(string)))
{ //!= null check has no effect at all
bothProperties.Obj2.SetValue(persEncrypt, encryptValue, null); //errorLine
}
}
}
return persEncrypt;
}
That is what I came up with until now.
I have, of course, searched for other solutions like this one. This, after applying some own changes, didn't return any errors, but it didn't save any encrypted strings into the class persEncrypt. What I concluded was, from that test, is that it was testing if the value in the second class(persEncrypt in my example) from the particular property was null, while it shouldn't do that, it should make a new instance of that variable and save it in the object class, but removing that check gave me the same error.
you're just .Zip-ing the two lists of PropertyInfo objects, which simply iterates through both lists and doesn't check or sort for any sort of matching. This could result in erroneous behavior depending on the order in which properties appear - consider using a .Join instead to match property names.
This code doesn't check for an indexer on the property before attempting to assign to it without one - any indexed property which is of type string will make it to this point and then throw an exception when you try to set it.
Because this code is calling into Properties, there's the possibility an exception is being thrown by the code of the Property itself. This is where a StackTrace from your exception could reveal much more about what's happening.
Your code also checks for a property of type string directly - when using reflection you should use IsAssignableFrom instead in order to allow for inherited types, though that is unlikely the issue in this one case.
I'm looking for a type/method of collection where I can add an object to a group of objects, then separately change the attributes of that object, and have those changes reflected in the object within the collection.
I've heard that List<T> adds values by reference, so I figured that the reference would be to the same object. In other words, I assumed:
List<string> valuesList = new List<string>();
string initialValue = "Alpha";
valuesList.Add(initialValue);
initialValue = "Bravo";
bool incorrectAssumption = (valuesList[0] == "Bravo");
I had hoped that 'valuesList' would then contain the new value, "Bravo." Tried it out and I realized that the List copies the reference, it doesn't absorb it, so valueList still only has the "Alpha" value. Are there any ways to use a collection as a legitimate handful of the objects they contain?
And in case it helps to see the actual business need....
List<BaseWidget> widgets = new List<BaseWidget>();
DerivedWidget specialWidget = new DerivedWidget();
DerivedWidget extraSpecialWidget = new DerivedWidget();
widgets.Add(specialWidget);
widgets.Add(extraSpecialWidget);
specialWidget.Run();
extraSpecialWidget.Run();
if (!widgets.Any(x => x.RunSuccessfully)) return false;
(Where the Run() method sets the RunSuccessfully property, which I'd like to have reflected in the 'widgets' list.)
============================================================================
UPDATE
As it's been pointed out in the answers and comments, there's a bit of a discrepancy between the business need mock-up and the dry-run example. I'll condense the life-lesson into this: it seems List<objects> have their changes tracked, whereas List<values> don't.
Well. It seems that you don't understand what happens really. Here is great article about .net type internals.
Shortly, what happens in your example with strings:
You create list
You create variable initialValue of string type. Value of this variable stores in special local variables container. Because string is reference type, in container of local variables it contained as a pointer to object.
You create new string "Alpha", storing it in heap, and assign pointer (to this string) to your local variable.
Then you are adding object to list. In your List this object stored as pointer to somewhere.
Then you are changing content of local variable 'initialValue' by assign it to pointer to another string. So, now in local variable 'initialValue' is one pointer, in list is another pointer.
Well, what about solutions?
Wrap your string to some another class. Like this:
class Wrapper<T> {
public T Content {get;set;}
public Wrapper(T content) {
Content = content;
}
}
Usage:
void Main()
{
var valuesList = new List<Wrapper<string>>();
var initialValue = new Wrapper<string>("Alpha");
valuesList.Add(initialValue);
initialValue.Content = "Bravo";
Console.WriteLine(valuesList[0].Content);
}
A bit ugly syntax.
Use clojures:
void Main()
{
List<Func<string>> valuesList = new List<Func<string>>();
string initialValue = "Alpha";
valuesList.Add(() => initialValue);
initialValue = "Bravo";
Console.WriteLine(valuesList[0]() == "Bravo");
}
All references to non-value types will be passed by reference, List<T> or not. String is a value type, however, and will always be passed by value. They are also immutable, so any time you change one you're actually creating a new String.
For your example, you could create a wrapper type to contain your string, and store this in your List<T>.
It seems that your actual business case should work properly, unless they are declared as structs.
I am developing a windows 8 app, and i have some javascript that stores a serialized object into roaming settings, i.e:
var object = [{"id":1}, {"id":2}]
roamingSettings.values["example"] = JSON.stringify(object);
I also i have a c# part to the application (for running a background task), that needs to read that JSON, and turn it into an object so i can iterate over it. And this is where i am having some issues, i am using JSON.NET to do the work, but every thing i turn turns up with an error:
// this looks like "[{\"id\":1},{\"id\":2}]"
string exampleJSON = roaming.Values["example"].ToString();
// dont know if this is correct:
List<string> example = JsonConvert.DeserializeObject<List<string>>(exampleJSON );
That give an error of:
Error reading string. Unexpected token: StartObject. Path '[0]', line 1, position 2.
So i am at a loss of what to do, i have been working on it for last few hours, and i am quite unfamiliar with c#, so resorting to the help of stackoverflow ;D
Thanks in advance for any help :)
Andy
Json.Net has a nice method DeserializeAnonymousType. No need to declare a temporary class.
string json = "[{\"id\":1},{\"id\":2}]";
var anonymous = new []{new{id=0}};
anonymous = JsonConvert.DeserializeAnonymousType(json,anonymous);
foreach (var item in anonymous)
{
Console.WriteLine(item.id);
}
You can even use the dynamic keyword
dynamic dynObj = JsonConvert.DeserializeObject(json);
foreach (var item in dynObj)
{
Console.WriteLine(item.id);
}
You are trying to parse your JSON array into a List of strings, which doesn't work. The JSON object you provide is actually a list of objects containing an integer property called 'id'.
Perhaps try creating a class (say, MyClass) with just that property, and deserialize into List.
Your json containts a collection of objects with an id property, something like this:
class IdObject {
public int id { get; set; }
}
You could then do:
JsonConvert.DeserializeObject<List<IdObject>>(exampleJSON);
Because the IdObject class has a property id to match your json serialized value, it will be mapped back.
I'm trying to write a custom method to populate a ListView control using Generics:
private void BindDataToListView(List<T> containerItems)
{
this.View = View.Details;
this.GridLines = true;
this.FullRowSelect = true;
if (this.Items.Count > 0)
this.Items.Clear();
this.BeginUpdate();
int i = 0;
foreach (T item in containerItems)
{
// do something
}
this.EndUpdate();
}
The parameter containerItems can have many items since I'm using generics. But I get stuck in the foreach loop. How do I access the values in containerItems?
Do I have to use reflection on each instance of T in the foreach loop? I think I do to retrieve the property name. But once I have the property name of the type T, how do I retrieve the value?
The most common way of doing this (with winforms) is via TypeDescriptor; this allow you to use things DataTable the same as classes; the "full" pattern is quite complex (and involves checking for IListSource, ITypedList, etc; however, the short version is; to get the available properties:
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
To get a named property:
PropertDescriptor prop = props[propName];
To get a value for an instance (sourceObject):
object val = prop.GetValue(sourceObject);
To render a value as a string (using the designated converter):
string s = prop.Converter.ConvertToString(val);
You could limit T to an interface, and use that interface in the iteration.
What does T represent ?
Like it is now, it is a generic type and it can be ... anything.
So, what I would do, is create an interface IListViewBindable or something like that. That interface could then have a method 'CreateListViewItem' for instance.
Then, I would change the method, so that a constraint is applied to your type-parameter T, saying that T should implement IListViewBindable, like this:
public void BindDataToListView<T>( List<T> containerItems ) where T : IListViewBindable
{}
In your BindDataToListView method, you could then do this:
foreach( T item in containerItems )
{
this.Items.Add (item.CreateListViewItem());
}
If the items in the list are of totally unconstrained type, then you can treat them as simply of type object. You call GetType() to get the type of the object. On that you can call GetProperties() to get an array of PropertyInfo objects. And on those you can call GetValue() to retrieve the value of the property.
If you already know the name of a property, just call GetProperty() to retrieve it:
string valueAsString = item.GetType().GetProperty("Something")
.GetValue(item, null).ToString();
I don't completely understand what you're asking, but I think that this will point you in the right direction. Please ask for clarification if it looks like it can help and it's unclear.
You can access a given property of an object using reflection via
object o;
PropertyInfo info = o.GetType().GetProperty().GetProperty("NameOfPropertyIWant");
and you can get the value via
object value = info.GetValue(o, null);
Now, if you're going to be accessing a property of the same name on objects of various types, you should consider adding an interface
public interface IHasThePropertyIWant {
object NameOfPropertyIWant { get; }
}
Then you can enforce this via
void BindDataToListView(List<T> containerItems) where T : IHasThePropertyIWant
and use it in the look like so
foreach (T item in containerItems) {
object o = item.NameOfPropertyIWant;
// do something with o
}
ObjectListView uses reflection to do exactly what you are trying to do: populate a ListView using reflection. You could save yourself a lot of trouble by using it. It has already solved all the tricky problems you are going to encounter on this path.
If you really, really want to do it yourself, Marc's answer is (of course) completely correct.