List of properties not changing when set - c#

In a class constructor I have a instantiate a list containing properties:
public MDInstrument() : base()
{
// bidss = new TickData[] {Bid0};
Bids = new List<TickData> { Bid0, Bid1, Bid2, Bid3, Bid4, Bid5, Bid6, Bid7, Bid8, Bid9, Bid10, Bid0, Bid11, Bid13, Bid14, Bid15, Bid6, Bid17, Bid18, Bid19};
Offers = new List<TickData> { Ask0, Ask1, Ask2, Ask3, Ask4, Ask5, Ask6, Ask7, Ask8, Ask9, Ask10, Ask0, Ask11, Ask13, Ask14, Ask15, Ask6, Ask17, Ask18, Ask19};
}
A method in the class updates the object in the list but why is the object always null ?
I must be missing something

Your problem is that to begin with Bid{x} and Ask{x} have not been instantiated, i.e. they're null, and then you store a reference to those values, and of course the reference is null. When you then later on update Bid0 (for example), then that reference is updated, but nothing can know that this is intended to be stored within your set.
Suggest that you change your list to be an array of a fixed known size (here, 20) which will be all nulls to begin with. Then change your getter/setter accessors for the individual Bid items to actually the array internally. Then you also don't need all of those separate Bid{x}/Ask{x} variables.

Related

How can i access Structure property that is inside Hashtable? [duplicate]

This question already has answers here:
Modify Struct variable in a Dictionary
(5 answers)
Closed 7 years ago.
I have the following code that will modify a property inside a structure, and the structure is inside a hash table. Each item in hash table has key of (Int) data type and key of (struct Bag), here is the code i have:
struct Bag {
string apple_type;
string orange_type;
};
// Make a new hashtable that will have a key of (int) data type, value of (Bag)
public static Hashtable bags = new Hashtable();
Then i have a method that will read data from a data base reading rows and adding as long there is a row it will add an item (bag(object)) to the hashtable:
public void initHashtbl(){
OleDbConnection db_connector = new OleDbConnection(connection_string);
// Open connection to oracle
db_connector.Open();
OleDbCommand sql_commander = new OleDbCommand(sql_statement, db_connector);
OleDbDataReader data_Reader = sql_commander.ExecuteReader();
// Read data from sql db server and store it in memory ...
Bag tempBag = new Bag();
// row counter used for list view
int row_counter = 0;
while (data_Reader.Read()) { // Keep reading data from memory until there is no row
tempBag.apple_type = data_Reader[0].ToString();
bags.Add(row_counter, tempBag);
row_counter++;
}
for(int bag_item=0;bag_item < bags.Count;bag_item++){
// Get orange type value from another method that uses another sql statement from another table in db ..
((bag) bags[bag_item]).orange_type = getOrangeType(((bag) bags[bag_item]).apple_type);
}
}
How can i access the property of structure that is already inside hash table at later time if i wanted to access it?
Edit:
I'm getting this error:
"Cannot modify the result of an unboxing conversion."
Dictionary will not allow me to modify that directly
Neither will a Hashtable. This has nothing to do with Hashtable vs Dictionary. The problem is that your "value" in either case is a value type, so you can't modify it directly within the collection. If you really need a struct, then you'll have to create a new value and put it back into the hashtable:
bags.Add(1, new Bag() {apple_type="apple1",orange_type="orange1"});
//((Bag)bags[1]).apple_type="apple2";
var bag = (Bag)bags[1];
bag.apple_type = "appple2";
bags[1] = bag;
But mutable structs are generally bad, so I would either get the value of the struct right the first time (rather than modifying it ourside of the initial load loop) :
// row counter used for list view
int row_counter = 0;
while (data_Reader.Read()) { // Keep reading data from memory until there is no row
{
var appleType = data_Reader[0].ToString();
Bag tempBag = new Bag() {
apple_type = appleType,
orange_type = getOrangeType(appleType)
};
bags.Add(row_counter, tempBag);
row_counter++;
}
or use a class.
Note that the same code works exactly the same way whether you use a Hashtable or a Dictionary.
Also, since your "key" is just an incrementing number (and not tied to the value at all), you could just as well use a List<Bag> and access the items by index.
This code worked for me to read an item:
string orangeType = ((Bag) bags[0]).orange_type;
To modify an item, I think you must create a new Bag and replace the existing one like this:
bags[0] = newBag;
If you try to modify the properties of a bag in the HashTable, then you get the error you reported above.
Because of how value types work, the boxed Bag is a copy of the original, and "unboxing" it by casting back to Bag creates yet another copy. From the C# language spec:
When a value of a value type is converted to type object, an object
instance, also called a “box,” is allocated to hold the value, and the
value is copied into that box. Conversely, when an object reference is
cast to a value type, a check is made that the referenced object is a
box of the correct value type, and, if the check succeeds, the value
in the box is copied out.
Modifying the copy wouldn't change the original anyway, so it wouldn't make much sense to allow it.
Corrections:
To fix your error and to allow modifications to your HashTable of Bag's you should change your value type to reference type:
public class Bag
{
public string apple_type { get; set; }
public string orange_type { get; set; }
};

Object does not match target type PropertyInfo SetValue - one class to another

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.

How to use lambda statements to initialize UIPropertyMetaData in WPF

I know this is basic, but I'm not getting it. I simply wish to initialize the dependency property Dashes as a double collection using the lambda operator.
What is the proper syntax?
Thank you.
public static readonly DependencyProperty DashesProperty =
DependencyProperty.Register("Dashes", typeof(DoubleCollection), typeof(CustomTextBlock),
new UIPropertyMetadata(
() =>
{
DoubleCollection d = new DoubleCollection();
d.Add(4);
d.Add(4);
return d;
}
));
First of all you should avoid passing default value for reference types in DP metadata because that will be shared across all instances of containing class which you didn't intend to.
Say, you declared two instances of CustomTextBlock, then both instances will refer to same list and any modification in list will be transparent to both instances. Unless you explicitly setting it from constructor or somewhere else.
Be careful with default values of DP for reference types.
Anyhow, if you still want it, here how it is done:
new UIPropertyMetadata(new DoubleCollection() { 4, 5 })
UPDATE:
If you pass default value in metadata, then DoubleCollection's gets freezed automatically i.e. you can't add/delete from the collection in that case.
var dashesCollection = new CustomTextBlock().Dashes.Add(5); // Will throw exception.
However, if you set it explicitly from constructor, it's not marked as Frozen and items can be added/deleted from the collection.
var dashesCollection = new CustomTextBlock().Dashes.Add(5); // Works fine.
So, essence is to set the value in constructor and not in metadata of DP identifier.
Unfortunately, that's not possible. You can only provide a value, not a value factory. The workaround is to initialize the property in the constructor:
public CustomTextBlock()
{
Dashes = new DoubleCollection {4, 4};
}
Actually, I just realized that since DoubleCollection is Freezable, passing an instance of DoubleCollection as the default value (as suggested by Rohit Vats) could work, as long as you call Freeze on it. You could do it like this:
public static readonly DependencyProperty DashesProperty =
DependencyProperty.Register("Dashes", typeof(DoubleCollection), typeof(CustomTextBlock),
new UIPropertyMetadata(CreateDefaultDashes()));
private static DoubleCollection CreateDefaultDashes()
{
var dashes = new DoubleCollection { 4, 4 };
dashes.Freeze();
return dashes;
}
This makes the collection immutable, which means it can safely be shared among instances of CustomTextBlock.
OK, actually it seems that the default value is automatically frozen, so you don't need to do anything special. It is safe as a default value, because it becomes immutable when it's frozen.

Creating a grab-bag (collection) of original references to objects

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.

How do I set arbitrary number of properties on generic object?

I want to be able to call a method that creates an object and sets properties of the object based on the parameters passed into the method. The number of parameters is arbitrary, but the catch is I don't want to use strings. I want to use the actual properties sort of like you do in lambda expressions.
I want to be able to call the method with something that might look like this:
controller.Create<Person>(f=>{f.Name = 'John', f.Age = 30})
or something along those lines where I use the actual property reference (f.Name) instead of a string representation of the property.
Another stipulation is that I don't want any work to be done before the method call. I'm writing this in a library, so I don't want the user to have to do anything except make the call and get back an object with the properties set to the values passed in.
You can do something like:
controller.Create<Person>(f => { f.Name = 'John'; f.Age = 30; })
The create method signature will be:
public T Create<T>(Action<T> propertySetter) where T : class {
T value = ...;
propertySetter(value);
return value;
}
where T : class is not strictly required here but if T is a value type, the modifications to its properties would be lost.

Categories

Resources