change propertyname base on variable [duplicate] - c#

This question already has an answer here:
Can I set a property value with Reflection?
(1 answer)
Closed 2 years ago.
I have a QoL problem that i can figure out myself. See my below code with some explenations
public void UpdateStock(long? instID, float? Value, int counter,string KpiName)
{
{
List<KpiReturn> updateKpi = new List<KpiReturn>();
updateKpi.Add(new KpiReturn { instID = instID, KpiName = Value });
}
}
And a class with my properties looking like this:
public partial class KpiReturn
{
public long? instID { get; set; }
public double? peValue { get; set; }
public double? psValue { get; set; }
public double? pbValue { get; set; }
}
This code wont work because my kpiReturn dosent have a definition for "KpiName"
Right now i run 3 different if statements based on if i want the peValue,psValue,pbValue. But i want to add many more properties to this.
in the void UpdateStock code attached i have passed the string "psValue" to the KpiName.
is there any way that i can do to make the program understand that in the code
updateKpi.Add(new KpiReturn { instID = instID, KpiName = Value }
i want to pass the kpiName value instead of the actual name "kpiName"? ie psValue,pbValue or peValue

Sometimes it makes problems like this easier if you continue to break down the problem into smaller pieces. The right abstractions at the right level can be helpful which is the crux of #N-ate was suggesting when he mentioned breaking down the problem into smaller operations.
For example, so far you seem to have thought of the probem as requiring a big result object that holds everything. Sorta like this big ball of mud style object:
class KpiBigBallOfMudReturn
{
public long? instId { get; set; }
public double? peValue { get; set; }
public double? psValue { get; set; }
public double? pbValue { get; set; }
// lets keep adding many more properties to
// this class, make them nullable so we don't
// always have to set all of them....
// .. and more.. ...
}
But what you've also described is that you're creating values for that return separately and those things stand alone and have a name also. So if you create an abstraction around them it might look something like this:
class KpiValue
{
public string KpiId { get; set; }
public double Value { get; set; }
}
Here the KpiId is what you have as "KpiName" in your Update method.
#MarcGravell comment suggested using switches to select the right value based off name. Now that we have the pairs of name/values we can use a dictionary to do something similar - as #SeanSkelly suggested. We can replace the big ball of mud result object with something like this:
class KpiResult
{
readonly IDictionary<string, double> kpiValues;
public KpiResult(long instId, IEnumerable<KpiValue> values)
{
this.kpiValues = values.ToDictionary(k => k.KpiId, v => v.Value);
}
public double? this[string key]
{
get
{
if (this.kpiValues.TryGetValue(key, out var value))
return value;
return null;
}
}
}
Again this is just an example to illustrate the point that when you run into technical issues like this it's often helpful to see if you can solve them by making your design more SOLID

Related

Trying to set up Nested Object in C#, with computed field based on list

I am experimenting with a nested object class for an upcoming software project, in C#. I know how to do computed fields/properties within a class, at least as far as setting it programmatically with something like the date.
This is a little different. I am setting up a nested class like this:
string Test { get; set; }
List<Line> Detail { get; set; }
decimal Total {
get {
return TotalOf();
}
}
decimal TotalOf() {
var listQuery = this.Detail;
// This is where I'm trying to figure out how to do.
// I want the TotalOf function to return the sum of the
// Cost fields of the contained list items (Line is defined below).
// I will remove the "return 0;" eventually once
// I can figure out how to do the calculation.
return 0;
}
public class Line {
int indexOf { get; set; }
decimal Cost { get; set; }
}
That way, the field Total is automatically calculated rather than me having to compute it through the code consuming this class.
I have tried searching all over but I can't seem to find the right answer. I have plenty of time to do this, and worst case, I can just do it in the program consuming this class, but I thought I'd ask. When I hit the . after typing in this.Detail, the only aggregate function that comes up is Count.
I have tried to use the Detail.Sum function, hoping the Linq would bring up a lambda expression that I could then say "add up the Cost" but it won't come up.
I know this should be simple but I can't figure it out.
First, set access modifiers for Line properties like as public or other. Because, on default state it is private.
public class Line
{
public int indexOf { get; set; }
public decimal Cost { get; set; }
}
Then, set up root class like as LineCollection.
public class LineCollection
{
public class Line
{
public int indexOf { get; set; }
public decimal Cost { get; set; }
}
public string Test { get; set; }
public List<Line> Detail { get; set; }
public decimal Total { get; set; }
}
On LineCollection initialize default values for properties on constructor:
public class LineCollection
{
public class Line
{
public int indexOf { get; set; }
public decimal Cost { get; set; }
}
public string Test { get; set; }
public List<Line> Detail { get; set; }
public decimal Total { get; set; }
public LineCollection()
{
this.Test = string.Empty;
this.Detail = new List<Line>();
}
}
After this modify get/set accessors for Total property. I guess, property is read only and we not need to define set accessor.
public decimal Total
{
get
{
return this.Detail.Sum(x => x.Cost);
}
}
Code in get accessor automatically runs when we trying to get his value. Finally, we can run tests for checks.
LineCollection collection = new LineCollection();
collection.Detail.Add(new LineCollection.Line() { indexOf = 0, Cost = 43.3m });
collection.Detail.Add(new LineCollection.Line() { indexOf = 1, Cost = 23 });
collection.Detail.Add(new LineCollection.Line() { indexOf = 3, Cost = 56.21m });
Console.WriteLine(collection.Total.ToString());
It returns 122,51.
Think this method would work for you:
decimal TotalOf() {
return this.Detail.Select(line => line.Cost).Sum();
}
I believe this way also works:
decimal TotalOf() {
return this.Detail.Sum(line => line.Cost);
}
Hope this helps :)

C# EF Core converting object to string / get; set

I do get a stack overflow when trying to convert an object to a string in C#. I'm making an API Call to an endpoint and pass the response to this class. As the ef core does not support the datatype “object” I'm trying to convert this datatype to string to store it in the database as a column.
I have a class with various attributes like
public DateTime? start_date_local { get; set; }
public string? timezone { get; set; }
public double? utc_offset { get; set; }
some of them are from type object:
[NotMapped]
public object? start_latlng { get; set; }
As this datatype is not supported, I'm not mapping this to the DB, but I'm trying to convert this into a string and store it within a second datatype which can be inserted into the DB.
public string start_latlng2
{
get { return start_latlng2; }
set { start_latlng2 = Convert.ToString(start_latlng); }
}
This does not seem to work as I always get an error like:
Stack overflow.
Repeat 19126 times:
--------------------------------
at SportAnalytics.DataModel.Activity.get_start_latlng2()
--------------------------------
at DynamicClass.lambda_method171(System.Runtime.CompilerServices.Closure, Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.EnsureOriginalValues()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntrySubscriber.SnapshotAndSubscribe(Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry)
Am I doing something wrong? Is there a better way to achieve what I'm trying to do?
The StackoverflowException comes from the wrong definition of your property. You should write it with an explicit back field.
private string _start_latlng2;
public string start_latlng2
{
get { return _start_latlng2; }
set { _start_latlng2 = value; }
}
In your case you should use an explicit read-only property, that will be called when needed:
public string start_latlng2
{
get { return start_latlng == null ? null : Convert.ToString(start_latlng); }
}
You can try like this
public class Test{
public Test1 start_latlng {get;set;}
}
public class Test1{
public string Attr1 {get;set}
public string Attr2 {get;set}
}
#Oliver
sorry for asking once again a silly questions, but I just got started with C# a few weeks back.
I have now set something like this:
[NotMapped]
public object? start_latlng { get; set; } // was object
private string? _start_latlng2;
public string? start_latlng2
{
get { return start_latlng == null ? null : Convert.ToString(start_latlng); }
set { _start_latlng2 = value; }
}
If I run the debugger once again, I can see that the original object is an array like ["49,11", "49,12"], the start_latlng2 is also set like a string "["49,11", "49,12"]" which is fine and ok for me to be added to the database like this, but the column in sql keeps empty and I don´t know why because the property in the debugger is set correctly.
Can you once again maybe quickly explain how your suggestion
private string _start_latlng2;
public string start_latlng2
{
get { return _start_latlng2; }
set { _start_latlng2 = value; }
}
corresponds to transforming an object to an string? Your suggestion here just covers how you can access private fields with those getters and setters or? I really would like to understand how I can convert an object to string working with getters and setters. Maybe you can explain that once more, thank you very miuch Oliver!

Config Automapper to ignore type when it's an inner-inner property but not inner property

This one takes a little explaining. I have a set of types such that;
public class Child
{
public int ID { get; set;}
}
public class MayHaveChild
{
public Child Value { get; set; }
public int MayID { get; set; }
}
public class MustNotHaveChild { get; set; }
{
public List<MayHaveChild> MayValues { get; set; }
}
In the above scenario, I want any mapping of MayHaveChild to have the values for the Child object, except when I have mapped MustNotHaveChild. E.g.;
When I have
//...some code
MayHave obj = Mapper.Map<MayHaveChild>(childObj);
// I want to be able to access obj.Child.ID
But when I have
//...some code
MustNotHave obj = Mapper.Map<MustNotHaveChild>(notHaveObj);
// I want to be able to access obj.MayValues[0].MayID but
// *not* obj.MayValues[0].Value
I've been through the automapper documention on nesting, polymorphism, lists, etc and I can't find anything that quite matches what I want.
I could solve this by having a inheriting the MayHave class to a MustNotHave variant but this would involve changing quite a lot of existing code. Is there a way to configure Automapper in the manner I need?
I couldn't find a way to configure AutoMapper the way I wanted without going down the inheritance route - though this proved less problematic than I thought. I did something like the following;
public class NoChild : MayHaveChild
{
}
public class MustNotHaveChild { get; set; }
{
// \/--datatype change here
public List<NoChild> MayValues { get; set; }
}
Then, later in the AutoMapper config;
Mapper.CreateMap<MayHave, NoChild>()
.ForMember(c => c.Child, opt => opt.Ignore());

Using {set; get;} instead of {get; set;}

In C# and its cousin languages, we always use
public string SomeString { get; set;}
But you can also use ( I found this out only recently and while fooling around with the compiler )
public string SomeString { set; get; }
I do not have any formal training in programming and everything is self-tought. I have been using { get; set; } without any thought just like we use 1 + 1 = 2 Is the order of { get; set; } just a convention or is it necessary to maintain this order or is it some remnant of a bygone era of C history like the way we define conventional electric current flowing from positive to the negative terminal when it is actually the other way around?
It is purely a convention. It makes no difference which order they appear in.
There is no difference.
It is exactly as if you had implemented the getter first in your class body, and the setter after it. The functions would still do exactly the same:
public String getSomeString() { return someString; }
public void setSomeString(String value) { someString=value; }
Whether they are written in that order
public void setSomeString(String value) { someString=value; }
public String getSomeString() { return someString; }
or the opposite. Wouldn't they?
I would however suggest to stick to one order in your code. Less entropy is always better :)
There is no difference.
According to the C# Language Specification http://msdn.microsoft.com/en-us/library/ms228593.aspx, 10.7.2 Accessors (page 324)
The accessor-declarations of a property specify the executable
statements associated with reading and writing that property.
accessor-declarations:
get-accessor-declaration set-accessor-declaration
set-accessor-declaration get-accessor-declaration
As shown it states either order has the same effect
Internally Get and Set are methods like this
private PropertyType Get() {}
private Set(value as PropertyType) {}
Since order of declaration of methods is not important, same case goes here.
MSDN:
The body of the get accessor is similar to that of a method. It must return a value of the property type.
The set accessor is similar to a method that returns void. It uses an implicit parameter called value, whose type is the type of the property.
{ get; set; } is just a shortcut so you don't have to write getters and setters for every field you want to expose. It's the same as when you write
public string GetSomeString() { }
public void SetSomeString(string value) { }
Does it matter, which one you write first? Of course not.
Just a convention you can use any of these when defining parameters:
public string SomeString { get; set; }
public string SomeString2 { set; get; }
public string someString2;
public string SomeString21
{
get { return someString2; }
set { someString2 = value; }
}
public string SomeString22
{
set { someString2 = value; }
get { return someString2; }
}
public string SomeString23
{
set { someString2 = value; }
}
public string SomeString24
{
get { return someString2; }
}
As others have already pointed out, there is no difference and it is just a convention. But to prove that up, you can see how compiler actually treats your code, given the following:
public class C
{
public string SomeString { get; set;}
public string SomeString2 { set; get; }
}
This will be treated as:
public class C
{
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string <SomeString>k__BackingField;
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string <SomeString2>k__BackingField;
public string SomeString
{
[CompilerGenerated]
get
{
return <SomeString>k__BackingField;
}
[CompilerGenerated]
set
{
<SomeString>k__BackingField = value;
}
}
public string SomeString2
{
[CompilerGenerated]
get
{
return <SomeString2>k__BackingField;
}
[CompilerGenerated]
set
{
<SomeString2>k__BackingField = value;
}
}
}
As you can see, in both of them a new BackingField is generated by compiler and the body of two properties are same exactly.
The reference.

Protocol Buffers and Typesafe Enums in C#

I'm trying to serialize some typesafe enums which I implemented like the answer to this question. When I serialize an object containing a reference to, say, FORMS (from the answer I linked), I'd like, upon deserialization, to restore the reference to the static field FORMS.
I have a solution but it seems kind crappy since I'd have to add it to any class that contained a typesafe enum. It pretty much just uses callbacks to store and retrieve the enum's value field:
public class SomethingContainingAnAuthenticationMethod
{
[ProtoMember(1)]
public int AuthenticationMethodDataTransferField { get; set; }
public AuthenticationMethod AuthenticationMethod { get; set; }
[ProtoBeforeSerialization]
public void PopulateDataTransferField()
{
AuthenticationMethodDataTransferField = AuthenticationMethod.value;
}
[ProtoAfterDeserialization]
public void PopulateAuthenticationMethodField()
{
AuthenticationMethod = AuthenticationMethod.FromInt(AuthenticationMethodDataTransferField);
}
}
Any other ideas would be much appreciated.
With the answer in the linked example, the simplest approach is probably:
[ProtoContract]
public class SomethingContainingAnAuthenticationMethod
{
[ProtoMember(1)]
private int? AuthenticationMethodDataTransferField {
get { return AuthenticationMethod == null ? (int?)null
: AuthenticationMethod.Value; }
set { AuthenticationMethod = value == null ? null
: AuthenticationMethod.FromInt(value.Value); }
}
public AuthenticationMethod AuthenticationMethod { get; set; }
}
which avoids an extra field and any callbacks. Something similar could also be done via a surrogate-type, but the above should work for most simple cases.
The mechanism for serializing an enum member is pretty simple:
[ProtoContract]
public class SomethingContainingAnAuthenticationMethod
{
[ProtoMember(1)]
public AuthenticationMethod AuthenticationMethod { get; set; }
}
And... that's about it. The minor gotcha sometimes (which might raise errors about not being able to find an enum with value) is the implicit-zero behaviour, but that is simply avoided:
[ProtoMember(1, IsRequired=true)]
public AuthenticationMethod AuthenticationMethod { get; set; }

Categories