Changing object property while storing it in list - c#

lets say i have class with a lot of redundant properties and i want to store them in list, dictionary or whatever
public class Foo
{
public Bar Bar1 {get;set;}
public Bar Bar2 {get;set;}
public Bar Bar3 {get;set;}
public Buzz Buzz1 {get;set;}
public Buzz Buzz2 {get;set;}
public Buzz Buzz3 {get;set;}
public void UpdateObject(Buzz newValue)
{
var dict = new List<KeyValuePair<Bar, Func<Buzz >>>()
{
new KeyValuePair<Bar, Func<Buzz>>(this.Bar1 ,()=>this.Buzz1),
new KeyValuePair<Bar, Func<Buzz>>(this.Bar2 ,() => this.Buzz2 ),
new KeyValuePair<Bar, Func<Buzz>>(this.Bar3 ,() => this.Buzz3 )
};
foreach (var item in dict)
{
if (true)
{
var value = item.Value.Invoke();
value = newValue;
}
}
}
}
of course value is changed but Foo's Buzz1/2/3 property is not. How can i store some kind of reference to object's property in list, get this item and change object's value?

Instead of the key value pairs with a key and a setter, store a key, a getter, and a setter:
List<Tuple<Bar, Func<Buzz>, Action<Buzz>>
Action<Buzz> is a lambda that takes a new value for that Buzz as a parameter.
var dict = new List<Tuple<Bar, Func<Buzz>, Action<Buzz>>
{
new Tuple<Bar, Func<Buzz>, Action<Buzz>(this.Bar1 ,()=>this.Buzz1, x => this.Buzz1 = x),
// ...etc...
};
Not sure why you're doing this, but that'll work.
If it were me, instead of a Tuple or KeyValuePair, I'd write a ThingReference<T> class that takes the two lambdas, and store those in a Dictionary<Bar, ThingReference<Buzz>>.

Related

How select derived props in Aggregate function with 2 class

Plz help with System.Linq.Aggregate
I have the following class
public class MainClass
{
public ClassA someProp { get; set; }
public ClassA someProp2 { get; set; }
}
public class ClassA
{
public virtual Type Types => Type.None;
}
public class ClassB:ClassA
{
public override Type Types => Type.Default;
public string FieldName { get; set; }
}
public class ClassC:ClassA
{
public override Type Types => Type.Value;
public int FieldValue { get; set; }
}
And i want to get FieldName if it is filled in ClassB or the value from ClassC if it is also filled for someProp2 and someProp
I understand how to get 1 value
//for get name
IEnumerable<string> values = entities
.Where(x=>x.someProp!=null || x.someProp2!=null)
.SelectMany(mainClass => new[] {mainClass.someProp,mainClass.someProp2 })
.OfType<ClassB>()
.Select(classB => classB.FieldName)
//for get value
IEnumerable<int> values = entities
.Where(x=>x.someProp!=null || x.someProp2!=null)
.SelectMany(mainClass => new[] {mainClass.someProp,mainClass.someProp2 })
.OfType<ClassC>()
.Select(classC => classC.FieldValue)
but I don’t understand how to get 2 values in 1 requests, because there will be type 2 classes ClassB and ClassC
Probably the best way would be through the Aggregate method!
Tell me how to make the conditions for the selection and the Aggregate method itself
If you want to use .Aggregate() to achieve your goal, I would suggest that you use an overload that lets you define a seed in addition to the accumulator function after flattening the property pairs.
It could be implemented as follows:
IEnumerable<string> values = entities
.SelectMany(ent => new[] { ent.someProp, ent.someProp2 })
.Aggregate(new List<string>(),
( fields, property ) =>
{
if (property is ClassB)
{
fields.Add(((ClassB)property).FieldName);
}
else if (property is ClassC)
{
fields.Add(((ClassC)property).FieldValue.ToString());
}
return fields;
});
Here, our seed is
new List<string>()
and our accumulator function is
( fields, property ) =>
{
// accumulation logic
return fields;
}
, containing the accumulator value parameter fields and element parameter property.
Our seed is the initial value of our accumulator value. For the first property in the flattened property collection (provided by the .SelectMany()), our accumulator value (fields) is therefore an empty list of strings.
For each element (property), field values are extraced based on the property's class type:
if property is a ClassB, FieldName is extracted and added to our accumulator value.
if property is a ClassC, FieldValue is extracted, and its string value is added to our accumulator value.
(if property is neither of those classes, nothing is added to fields).
After conditionally adding a field value to fields, fields is returned from the accumulator function to be used as the accumulator value in the next iteration of the accumulator function (i.e. for the next property in the flattened collection).
For entities given as follows:
List<MainClass> entities = new()
{
new()
{
someProp = new ClassC() { FieldValue = 4 },
someProp2 = new ClassB() { FieldName = "Flower" }
},
new()
{
someProp = new ClassA() { },
someProp2 = new ClassC() { FieldValue = 7 }
}
};
, the resulting values will contain:
4
Flower
7
Example fiddle here.

Retrieve Key at Index with For Loop

I feel as though I must be missing something very obvious, or C# is simply lacking a feature I've come to expect.
There are typically three for loops in programming.
#1 for (iterator; limit; increment) {}
Increments the iterator after each loop, until it hits the limit.
#2 for (key in object) {}
Assigns key the value of the left-half of the key:value pair at each entry of object.
#3 foreach (value in object) {}
Assigns value the value of the right-half of the key:value pair at each entry of object.
I'm aware that foreach can use a KeyValuePair<TKey,TValue>, but this necessitates assigning a much larger variable the reference to key and value. I don't care about the value, nor do I want to datatype it.
Where is #2 for in for C#?
You can do a foreach (var key in object.keys) (assuming object is a Dictionary) :
Dictionary<object, object> dict = new Dictionary<object, object>();
foreach (var key in dict.Keys)
{
var value = dict[key]; //Not required
}
You could also iterate through Values instead of Keys...but of course it would be impossible to retrieve the corresponding key.
In adition to #MikeH,
if your intention is to iterate over pure object to get Variable Names as Key and its values as values then you can do this with reflection. here is the example
public class Test
{
public string Prop1 {get; set;}
public string Prop2 {get; set;}
public string Prop3 {get; set;}
public string Prop4 {get; set;}
}
public class Program
{
public static void Main()
{
var test = new Test(){
Prop1 = "Test1",
Prop2 = "Test2",
Prop3 = "Test3",
Prop4 = "Test4"
};
foreach (var property in test.GetType().GetProperties())
{
Console.WriteLine("{0} = {1}", property.Name, property.GetValue(test));
}
}
}
besides, If you prefer to use dictionary again you can use
var dict = test.GetType().GetProperties().ToDictionary(x => x.Name, x=> x.GetValue(test));
foreach (var key in dict.Keys)
Console.WriteLine("{0} = {1}", key, dict[key]);

How do I use an object I only know the name of?

I'm working on a project at the moment that will make use of a certain kind of object (which we will call "Machine" in this case. This type of object has parameters, methods etc. pp. and I want to use its methods.
In this special case I will have a text field that allows the user to alter a certain property of an object of my own class, lets call it "Name" for simplicity. This property "Name" can be changed by typing a Name into a text field that is available to the user. Validating this text field will call a method from "Machine" for a certain object of that class which can be chosen from a ComboBox somewhere else on that page.
As these objects are created dynamicly, I have no idea how many of these objects there are and how they are called in particular, I only know that they exist.
How would you approach this kind of situation? Is there any way that you can basicly say "treat it as XY and use its methods as if you were sure it was of a certain type"? (Like a cast?)
Or would you solve this problem in other ways?
Use dynamic.
dynamic d = machine as dynamic;
d.Name = userInput;
That said, if you can force these object to implement an interface with the properties you care about your code will be faster and safer.
You can benefit from using dictionary collection :
class MyClass
{
public string Prop1 { get; private set; }
public int Prop2 { get; private set; }
public double Prop3 { get; private set; }
public Dictionary<string, Action<object>> Updater { get; private set; }
public MyClass()
{
Updater = new Dictionary<string, Action<object>>()
{
{"Prop1", o => Prop1 = o as string},
{"Prop2", o => Prop2 = (int)o},
{"Prop3", o => Prop3 = (double)o},
};
}
}
class Class27
{
static void Main()
{
Dictionary<string, MyClass> instances = new Dictionary<string, MyClass>();
instances.Add("First", new MyClass());
instances["First"].Updater["Prop1"]("hello");
instances["First"].Updater["Prop2"](10);
Console.WriteLine(instances["First"].Prop1);
Console.WriteLine(instances["First"].Prop2);
}
}
Output: hello, 10

automapper map dynamic object

I am working with Automapper and need to achieve the following mapping but not sure how it can be done.
I want to map a Dictionary object to a dynamic object, so that the key is the property on the object and the value of the dictionary is the value of property in dynamic object.
Can this be achieve with automapper and if so, how?
You can simply get Dictionary from ExpandoObject and fill it with original dictionary values
void Main()
{
AutoMapper.Mapper.CreateMap<Dictionary<string, object>, dynamic>()
.ConstructUsing(CreateDynamicFromDictionary);
var dictionary = new Dictionary<string, object>();
dictionary.Add("Name", "Ilya");
dynamic dyn = Mapper.Map<dynamic>(dictionary);
Console.WriteLine (dyn.Name);//prints Ilya
}
public dynamic CreateDynamicFromDictionary(IDictionary<string, object> dictionary)
{
dynamic dyn = new ExpandoObject();
var expandoDic = (IDictionary<string, object>)dyn;
dictionary.ToList()
.ForEach(keyValue => expandoDic.Add(keyValue.Key, keyValue.Value));
return dyn;
}
Here's en example, but if you drop a comment or elaborate your post it could be more descriptive. Given this class:
class Foo
{
public Foo(int bar, string baz)
{
Bar = bar;
Baz = baz;
}
public int Bar { get; set; }
public string Baz { get; set; }
}
You can create a dictionary of its public instance properties and values this way:
var valuesByProperty = foo.GetType().
GetProperties(BindingFlags.Public | BindingFlags.Instance).
ToDictionary(p => p, p => p.GetValue(foo));
If you want to include more or different results, specify different BindingFlags in the GetProperties method. If this doesn't answer your question, please leave a comment.
Alternatively, assuming you're working with a dynamic object and anonymous types, the approach is similar. The following example, clearly, doesn't require the class Foo.
dynamic foo = new {Bar = 42, Baz = "baz"};
Type fooType = foo.GetType();
var valuesByProperty = fooType.
GetProperties(BindingFlags.Public | BindingFlags.Instance).
ToDictionary(p => p, p => p.GetValue(foo));

Convert Dictionary<string, object> to a collection of objects with key

Is there a way to convert Dictionary<string, obj> to collection of objects such that each single object in the collection includes the key as another property
Here is the class def for obj
class someclass
{
string property1;
string property2;
}
After conversion, I am expecting each object in the collection to be like
obj.property1
obj.property2
obj.Key
I have been struggling with this since along time and I seek some help. any ideas?
thanks in advance.
Something like
var myCollection = from de in myDictionary
select new
{
de.Value.property1,
de.Value.property2,
de.Key
}.ToList(); // or .ToArray()
should do the trick.
That will return a List of a new anonymous type with the properties you requested.
You could also(in addition to the anonymous type apporach) use a List<Tuple<string, string, string>>:
var list= dictionary
.Select(kv => Tuple.Create(kv.Value.property1, kv.Value.property2, kv.Key))
.ToList();
foreach(var item in list)
{
Console.WriteLine("property1:{0 property2:{1} key:{2}"
, item.Item1
, item.Item2
, item.Item3);
}
The advantage over an anonymous type is that you can return the Tuple easily from a method.
Edit: A third option(my favorite) is simply to create instances of a class that you've declared somewhere. That's the ideal way. I don't know why i thought that you want a class "on the fly".
class someOtherClass
{
public string property1{ get; set; };
public string property2{ get; set; };
public string Key{ get; set; };
}
List<someOtherClass> objects = dictionary
.Select(kv => new someOtherClass(){
property1 = kv.Value.property1,
property2 = kv.Value.property2,
Key = kv.Key
})
.ToList();
You may use anonymous type if you don't want to store the result like this:
In case you just wana use it as datasource for example.
var res = myDictionary.Select(pair => new { pair.Key, pair.Value.Property1, pair.Value.Property2 });
The other answers are good, so this is just a supplement.
You could use arrays of Length three:
var arrays = myDictionary
.Select(kv => new[] { kv.Value.property1, kv.Value.property2, kv.Key, });
Or you could write a new class
class SomeclassAndKey
{
public string property1;
public string property1;
public string Key;
}
and then say
var someclassAndKeys = myDictionary
.Select(kv => new SomeclassAndKey { property1 = kv.Value.property1, property2 = kv.Value.property2, Key = kv.Key, });
In each case you could append .ToList() if you wanted not to defer enumeration and get a full List<> out.

Categories