chaps/chapettes, I understand there are questions related to this but this is somewhat different - all related questions I could find only used one parameter as an example. Anyways, to the point:
This year, I have converted source code written in Delphi to C#. Beyond this, the scope of my tasks has been to optimize and generally improve the code base. The source code has been written by a handful of individuals, each with no knowledge or experience of software engineering principles or techniques - so some of the code is abismal.
Anyhow, perhaps someone can provide a suggestion/solution to my quarrels:
Currently, in C# have a class for storing 9 values:
class StoreStruct
{
int A1 { get; set;}
int B1 { get; set;}
int C1 { get; set;}
int A2 { get; set;}
int B2 { get; set;}
int C2 { get; set;}
int A3 { get; set;}
int B3 { get; set;}
int C3 { get; set;}
}
Now what I have an issue with is that, ideally, I would like to pass the properties of this class into methods by ref. However, I know I can't do this. Instead the source code works by creating temp local variables, passes these by ref and then assigns the class properties to these values. This can be seen as follows:
private void MethodA()
{
var temp = new StoreStruct();
var a1 = 0;
var b1 = 0;
var c1 = 0;
var a2 = 0;
var b2 = 0;
var c2 = 0;
var a3 = 0;
var b3 = 0;
var c3 = 0;
if (expression1)
{
MethodB(ref a1, ref b1, ref c1, 1, 1);
temp.A1 = a1;
temp.B1 = b1;
temp.C1 = c1;
}
if (expression2)
{
MethodB(ref a2, ref b2, ref c2, 2, 2);
temp.A2 = a2;
temp.B2 = b2;
temp.C2 = c2;
}
if (expression3)
{
MethodB(ref a3, ref b3, ref c3, 3, 3);
temp.A3 = a3;
temp.B3 = b3;
temp.C3 = c3;
}
}
private void MethodB(ref int a, ref int b, ref int c, int num1, int num2)
{
a = num1 + num2;
b = num1 - num2;
c = num1 * num2;
}
What I would like to do in an ideal world:
MethodB(ref temp.A1, ref temp.B1, ref temp.C1, 1, 1);
From looking at other posts, I understand why this isn't catered for in C# and quite frankly I agree with the reasoning behind it. I have seen a few workarounds and a few suggestions in other posts but these only relate to an example with one method call and only one parameter being passed by ref. Does anyone have an elegant solution that would allow me to update the class properties in MethodB without having to pass temporary variables?
Just remove getters and setters from StoreStruct.
Personally I would use the workaround you did in your question. However if you really want it you would need to pass delegates in to the function that would assign the values for you then call them inside your function.
if (expression1)
{
MethodB((a) => temp1.A1 = a,
(b) => temp1.B1 = b,
(c) => temp1.C1 = c,
1, 1);
}
private void MethodB(Func<int> setA,
Func<int> setB,
Func<int> setC,
int num1, int num2)
{
setA(num1 + num2);
setB(num1 - num2);
setC(num1 * num2);
}
Properties are nothing but syntactic sugar for getter and setter function calls, which is why you cannot pass them by reference. In general in C# if you're using ref parameters, you're probably doing it wrong.
Simply pass the StoreStruct object, and let the function set the properties. A class is a reference type, so essentially all objects are passed "by reference" by default in C#.
I think modifying your StoreStruct will help with this, and eliminate a bunch of madness:
class Thing {
int A { get; set; }
int B { get; set; }
int C { get; set; }
}
class StoreStruct { // Not actually a struct!
public readonly Thing thing1;
public readonly Thing thing2;
public readonly Thing thing3;
}
Use:
private void MethodA()
{
var temp = new StoreStruct();
if (expression1)
{
MethodB(temp.thing1, 1, 1);
}
if (expression2)
{
MethodB(temp.thing2, 1, 1);
}
if (expression3)
{
MethodB(temp.thing3, 1, 1);
}
}
private void MethodB(Thing thing, int num1, int num2)
{
thing.A = num1 + num2;
thing.B = num1 - num2;
thing.C = num1 * num2;
}
Well, if it were me the first thing I'd do is try to get some real names here. What's an A1, B2, etc? Is it a cash register? A puppy? A space sled? Names should reflect what's going on. Next, ideally classes should modify their own data as much as possible, so I would tend to think in terms of passing the object and calling as few methods as possible on the object to do whatever modifications are needed rather than passing around a set of flags, especially if the latter have really obtuse names. Sorry if that seems like more of a general criticism, but it goes to what you mentioned about being tasked to improve the code base over time. (If they're really structs, I've always found properties to be overkill except insofar as they might aid debugging).
It seems that you are having three sets of values in your class. If you make a class of such a set, you can have three values in the class:
class ABC {
int A { get; set; }
int B { get; set; }
int C { get; set; }
}
class StoreStruct {
ABC ABC1 { get; set; }
ABC ABC2 { get; set; }
ABC ABC3 { get; set; }
public StoreStruct {
ABC1 = new ABC();
ABC2 = new ABC();
ABC3 = new ABC();
}
}
Now you can pass an ABC value into MethodB, and as that is a changeable set of values, you don't even need the ref keyword for the parameter:
private void MethodB(ABC abc, int num1, int num2) {
abc.A = num1 + num2;
abc.B = num1 - num2;
abc.C = num1 * num2;
}
Call:
MethodB(temp.ABC1, 1, 1);
You could also make MethodB a member of the class ABC, so that you don't pass the value to the method, you call the method on the value:
class ABC {
int A { get; set; }
int B { get; set; }
int C { get; set; }
public void MethodB(int num1, int num2) {
A = num1 + num2;
B = num1 - num2;
C = num1 * num2;
}
}
Usage:
temp.ABC1.MethodB(1, 1);
I agree with Jonathan's comment that you're probably doing something wrong and could encapsulate your state in a way that doesn't require passing by ref.
In order to do what you want, you can use a backing variable for the getters/setters.
private int _a1;
public int A1
{
get
{
return _a1;
}
set
{
_a1 = value;
}
}
public void Foo()
{
Bar(ref _a1);
}
It looks like you want to exchange every Property of a class. In the OOP-world the best way to do this is to send the complete class to the method, not just the properties:
public void MethodB(ref StoreStruct store) {
// store.A1=[...];
}
Wow, lots of answers to this question already. Well, here's another. You could try creating a class that can act as a reference to an integer like this:
class IntRef
{
private int value;
public IntRef(int value)
{
this.value = value;
}
public static implicit operator IntRef(int value)
{
return new IntRef(value);
}
public static implicit operator int(IntRef value)
{
return value.value;
}
}
Then change your int declarations and your ref int paremeters to IntRef.
Be aware that if you do this, though, that your set procedure may not run. You may have to move some of that code into the IntRef class or raise an event from IntRef so that the StoreStruct can react to the changed value.
Related
This is my object
public class Totals {
public int Total1 { get; set; }
public int Total2 { get; set; }
public int Total3 { get; set; }
public int Total4 { get; set; }
}
Incrementing the values of Total1 and Total2 using calculateTotals method
private Totals calculateTotals(Totals t) {
if (//condition) {
t.Total1 += 1;
} else {
t.Total2 += 1;
}
return t;
}
**Incrementing value of Total3 and Total4 of the same object with same conditions at a different location using different method calculateOtherTotals, at this point I only need to update Total3 and Total4 **
private Totals calculateOtherTotals(Totals t) {
if (//condition) {
t.Total3 += 1;
} else {
t.Total4 += 1;
}
return t;
}
I am new to c# , I need to increment the values Total1,Total2 and Total3,Total4 separately and the code which I have is working fine
Is there a way to improve my code?, how can I avoid creating two different methods which pretty much does the same logic on different properties? is there a way to create only 1 method to achieve my functionality?
You could do it this way, but essentially the amount of code doesn't change.
This adds a judgment:
Totals calculateTotals(Totals t, bool Flag)
{
//function1:
if (Flag)
{
if (true)
{ //(condition) {
t.Total1++;
}
else
{
t.Total2++;
}
}
//function2:
else
{
if (true)
{ //(condition) {
t.Total3++;
}
else
{
t.Total4++;
}
}
return t;
}
Call it like this:
Totals totals = new Totals();
totals.Total1=0;
totals.Total2=0;
totals.Total3=0;
totals.Total4=0;
calculateTotals(totals,true);//function1:
calculateTotals(totals,false);//function2:
Reflection is one way, though its slow and not a Domain Specific Language:
Type totalsType = typeof(Totals);
var totalToIncrement = condition;
PropertyInfo prop = totalsType.GetProperty("Total" + totalToIncrement);
prop.SetValue(null, 76);
Or perhaps you want to abstract the properties you're incrementing:
private Totals calculateTotals(Totals t)
{
bool condition = true;
AbstractAdds(ref t.Total1, ref t.Total2, condition);
return t;
}
private void AbstractAdds(ref int a, ref int b, bool condition = false)
{
if (condition)
{
a++;
}
else
{
b++;
}
}
}
public class Totals
{
public int Total1;//{ get; set; }
public int Total2;//{ get; set; }
public int Total3;//{ get; set; }
public int Total4;//{ get; set; }
}
I'd personally have a List<int> or int[3] and make the condition calculate the index 0-3:
var index = calcCondition;
Totals[index]++;
This way its extensible for more totals and you get inbuilt functions like LINQ, eg Totals.Sum().
Is there a way to improve my code?, how can I avoid creating two different methods which pretty much does the same logic on different properties? is there a way to create only 1 method to achieve my functionality?
Then it depends on how you want your method (function) to be. (E.g., how you define what your function will do and how your class and properties are characteristic—which, currently, many who want to help you still wonder about.)
Let me give another clear example.
Assume that you answer your additional requirement are:
My object has only 4 properties of "Total"
I want these new function to increment value only 1 when call, no need to add more than 1
This function is called from another class to modify my object value
I want my cool function name calculateOtherTotals being private, because of some unexplained reason such as “I don't like others knowing it exists”.
Then
public OtherClass{
Public Totals ExposeThePrivateCalculateOtherTotals(Totals t, bool IncrementT1 , bool IncrementT2 , bool IncrementT3, bool IncrementT4)
{
calculateOtherTotals(t, IncrementT1 , IncrementT2 , IncrementT3, IncrementT4);
}
Private Totals calculateOtherTotals(Totals t, bool IncrementT1 , bool IncrementT2 , bool IncrementT3, bool IncrementT4) {
if( IncrementT1 ) t.Total1 += 1; //choose your style
if( IncrementT2==true ) ++t.Total2;//choose your style
if( IncrementT3!=false ) t.Total3++; //choose your style
t.Total4 += IncrementT4==true?1:0;//choose your style
return t;
}
}
//In main (how to use)
Totals t= new Totals();
OtherClass doMyFunc = new OtherClass();
t = doMyFunc.ExposeThePrivateCalculateOtherTotals(t, true, false,false,false); // result of operation => t.total1 += 1;
t = doMyFunc.ExposeThePrivateCalculateOtherTotals(t, false, true,false,false); // result of operation => t.total2 += 1;
I am storing a int in schadstoffklasse so when calling the Car object like so (last int in brackets) :
PKW Kaefer = new PKW("VW", "Käfer", "K-GS-01", 1965, 9999, 1000, 30, 1);
I can either say 0, 1, 2.
Now when i write this Console.WriteLine(Kaefer.Schadstoffklasse)
to the console it obiously outputs 1 in this case.
I do want it to not say 1 i want for example....
0 = foo
1 = bar
2 = foobar
So it outputs to the console a string.
Here is what i have tried, which does not work.
private int schadstoffklasse;
public int Schadstoffklasse
{
get
{
return schadstoffklasse;
}
set
{
if (value == 0)
{
string foo = value.ToString();
foo = "BLABLALBA";
}
schadstoffklasse = value;
}
}
Thank you for having patience with a beginner
You can't have a property return mixed types. Your property of Schadstoffklasse is an int, therefore it can only ever return an int never a string.
There are a variety of different ways to accomplish this though, but without knowing more of how you are using this it'd be impossible to say which one you should do. I'd recommend either another property that has no setter and the getter looks at the other property, reads it's value and returns the string that you want or a method that does the same.
To expand on my suggestion:
public enum SchadstofklasseStrings
{
foo = 0,
bar = 1,
foobar = 2
}
public int Schadstoffklasse { get; set; }
public string SchadstoffklasseToString {
{
get
{
var stringValue = (SchadstofklasseStrings) Schadstoffklasse;
return stringValue.ToString();
}
}
Also, sorry for mutilating the German.
You can't change the type of a variable from int to string .
in this case i would create an array
["foo","bar","foobar"]
and use value of schadstoffklasse as an index
Console.WriteLine(Kaefer.myArray[Schadstoffklasse]);
Try this
private int schadstoffklasse;
public object Schadstoffklasse
{
get
{
if(this.schadstoffklasse==0)
return "foo";
if(this.schadstoffklasse==1)
return "bar";
if(this.schadstoffklasse==2)
return "foobar";
return "N/A";
}
set
{
this.schadstoffklasse=(int)value;
}
}
Note: The explain from user #gilliduck is useful. Consider this just
as a situational workaround.
I find enum helpful in situations like this since it is a collection of named integers. This is one example of how I might handle it.
void Main()
{
var Kaefer = new PKW("VW", "Käfer", "K-GS-01", 1965, 9999, 1000, 30, Schadstoffklassen.Bar);
Console.WriteLine(Enum.GetName(typeof(Schadstoffklassen), Kaefer.Schadstoffklasse));
// Output: Bar
}
public class PKW
{
private Schadstoffklassen schadstoffklasse;
public PKW(string v1, string v2, string v3, int v4, int v5, int v6, int v7, Schadstoffklassen _schadstoffklasse) {
schadstoffklasse = _schadstoffklasse;
}
public Schadstoffklassen Schadstoffklasse
{
get { return schadstoffklasse; }
set { schadstoffklasse = value; }
}
}
public enum Schadstoffklassen {
Foo = 0,
Bar = 1,
FooBar = 2
}
I got a class that I made static, but is it a bad option? Should it be a non static class?
I want to set two values in my class.
Is there any chance when you give properties values that there will be some kind of conflict when setting them and when getting them? If another user have the same target.
I got a page that calling this class.
One user hits the page and this happens.
Set the properties for the calculation
Run the void to calculate two properties
"Maybe some other functions runs and take some time"
Get the value of the two properties
But what if another user hits the page and sets other values and make either the first user's value incorrect. I guess that's possible?
Some other options I thought of is to either
Send all properties into the void as arguments and return a new class with my two values I need. (Not store them as a static property that could be changed by another user before it got used).
Create a new class with the properties (perhaps called BreakTime). Send that into the void as one argument. Return it, calculated.
Or you tell me what the best option is! :)
Here how it looks:
public static class BreakTimeCalculator
{
public static int BreakFromSec { get; private set; }
public static int BreakUntilSec { get; private set; }
public static int CustomBreakSec { get; set; }
public static int FromSec { get; set; }
public static int UntilSec { get; set; }
public static int Equlizer { get; set; }
public static void CalculateBreakFromAndBreakeUntil()
{
var taskLength = UntilSec - FromSec;
var middleOfTask = FromSec + (taskLength / 2);
var secondsToMoveLeft = middleOfTask % 300;
var amountEqualizers = CustomBreakSec / Equlizer;
var fiftyFifty = amountEqualizers % 2 == 0;
var leftSideEqualizers = fiftyFifty ? amountEqualizers / 2 : (amountEqualizers / 2) + 1;
BreakFromSec = middleOfTask - secondsToMoveLeft - (leftSideEqualizers * Equlizer);
BreakUntilSec = BreakFromSec + CustomBreakSec;
}
}
Never create static state unless you really, really have to as you'll set yourself up for a fall if you do. You make testing harder and you make the likelihood of a thread conflict (as you describe) happening much higher.
If you must set state in a class and then invoke methods, rather than just passing the values as parameters to the method, make it a non-static class. Also, you should preferably pass the values in via the constructor, rather than using properties.
Having said that, my approach to your problem would be to create a POCO to hold the result data and have a static method to do the calculation. Using C# 6 syntax, this would look like:
public class BreakTimeResult
{
public BreakTimeResult(int breakFromSec, int breakUntilSec)
{
BreakFromSec = breakFromSec;
BreakUntilSec = breakUntilSec;
}
public int BreakFromSec { get; }
public int BreakUntilSec { get; }
}
public static class BreakTimeCalculator
{
public static BreakTimeResult CalculateBreakFromAndBreakeUntil(int customBreakSec,
int fromSec,
int untilSec,
int equlizer)
{
var taskLength = untilSec - fromSec;
var middleOfTask = fromSec + (taskLength / 2);
var secondsToMoveLeft = middleOfTask % 300;
var amountEqualizers = customBreakSec / equlizer;
var fiftyFifty = amountEqualizers % 2 == 0;
var leftSideEqualizers = fiftyFifty
? amountEqualizers / 2
: (amountEqualizers / 2) + 1;
var breakFromSec = middleOfTask - secondsToMoveLeft - (leftSideEqualizers * equlizer);
var breakUntilSec = breakFromSec + customBreakSec;
return new BreakTimeResult(breakFromSec, breakUntilSec);
}
}
I got a question about constructors for my Windows Forms Application. First of all I want to say that I am new to programming.
The thing is this. I am making a constructor in another class that should hold different parameter values. In this case it should be int X, int Y, int Length, int Height. What I want to do here is to make the X, Y, Length and Height all random for my picturebox. I send code down below:
class Rechthoekcs
{
Random random = new Random();
public int Xas
{
get;
set;
}
public int Yas
{
get;
set;
}
public int Lengte
{
get;
set;
}
public int Breedte
{
get;
set;
}
public Rechthoekcs(int x, int y, int lengte, int breedte)
{
this.Xas = x;
this.Yas = y;
this.Lengte = lengte;
this.Breedte = breedte;
x = random.Next(x);
y = random.Next(y);
lengte = random.Next(lengte);
breedte = random.Next(breedte);
}
From my Form1 I want to call this class/constructor
But it gives me an error. It says "Does not contain a constructor with 0 arguments" and I know that because I typed the x, y, length and width. But I cannot add just the variables from the other class into the new parameter. I really don't get it. I find constructors very hard. I never know what parameters I should give with it...
I send the code down below from my Form1:
public partial class Form1 : Form
{
Rechthoekcs Rechthoek = new Rechthoekcs(.......);
public Form1()
{
InitializeComponent();
}
It it really frustrating for me. I tried looking up on the web and books and such but all the explanation about which parameters should be given for a constructor is not clear to me. Could someone explain this? Not understanding it drives me insane. Plus I am getting often stuck at these points..
public Rechthoekcs(int x, int y, int lengte, int breedte)
{
this.Xas = x;
this.Yas = y;
this.Lengte = lengte;
this.Breedte = breedte;
x = random.Next(x);
y = random.Next(y);
lengte = random.Next(lengte);
breedte = random.Next(breedte);
}
You are assigning the values of the parameters to your private Data Members before you do anything "randomizing" about them. You are simply changing the values of the parameters in your constructor without assigning them. Swap the order you do them in.
public Rechthoekcs(int x, int y, int lengte, int breedte)
{
x = random.Next(x);
y = random.Next(y);
lengte = random.Next(lengte);
breedte = random.Next(breedte);
this.Xas = x;
this.Yas = y;
this.Lengte = lengte;
this.Breedte = breedte;
}
Now you have successfully randomized your values that will be set to your data member variables ASSUMING that those variable you put in there actually exist, which they should. Better/more modular code would do this randomization where you create your object.
Ex: Object foo = new Object(new Random, new Random, new Random, new Random)
Not the answer OP is looking for, but this is how you solve "I don't yet know the value but I need to construct object anyway" version of the question.
You can delay requesting the data by passing Func<T> for each parameter instead of just T assuming the values actually will be available by the time they needed:
class UseDelayedValues
{
Func<int> x;
public UseDelayedValues(Func<int> x)
{
this.x = x;
}
public UseWithX(int other)
{
return other + x();
}
}
int value = 0;
var r = new UseDelayedValues(() => value);
value = 42;// get some value
Console.WriteLine(r.UseDelayedValues(1));
var delayedFromTextbox = new UseDelayedValues(() => int.Parse(textBox1.Value));
Lines using the UseDelayedValues can be spread over time. I.e. instance constructed in constructor, but value used only when form is shown by button click.
Hey I want to have something like that
int a=0;
a=5(be unchangeable);
a=3;
Console.WriteLine(a);//which will print 5 and not 3
so basically make declare the variable a number and have it be final and unchangeable, I tried looking around but I only found things that work as the int is declared and not as a new value for it is declared.
doesn't this work?
const int a = 5;
see const(C# reference)
const int a = 0;
The const keyword is used to modify a declaration of a field or local
variable. It specifies that the value of the field or the local
variable is constant, which means it cannot be modified.
Ref.
You want the const keyword.
const int a = 5;
From MSDN:
The const keyword is used to modify a declaration of a field or local variable. It specifies that the value of the field or the local variable cannot be modified.
EDIT: Your requirement sounds odd and not useful. But if you really need it, you'll have to create a custom type. I'd suggest a class with a bool property stating whether or not it's mutable or not.
public class MyCustomInt
{
public bool IsMutable { get; set; }
private int _myInt;
public int MyInt
{
get
{
return _myInt;
}
set
{
if(IsMutable)
{
_myInt = value;
}
}
}
public MyCustomInt(int val)
{
MyInt = val;
IsMutable = true;
}
}
Then when you use it:
MyCustomInt a = new MyCustomInt(0);
a.MyInt = 5;
a.IsMutable = false;
a.MyInt = 3; //Won't change here!
Console.WriteLine(a); //Prints 5 and not 3
That's about as good as you can get, I think.
use readonly:
as it can be changed by the constructor but then not again.
public class MyClass {
private readonly int a = 0;
public MyClass(int a) {
this.a = a;
}
public void DoSomethingWithA() {
Console.WriteLine(this.a);
//a = 5 // don't try this at home kids
}
}
new MyClass(5).DoSomethingWithA();
A nice comparison between const and readonly
You can use a constant with the const keyword.
const int a = 5;
but if you do that, you will not be allowed to change to another value.
You also can check the use of the pointers:
int x = 5;
int y = 3;
int *ptr1 = &x; // point to x memory address
int *ptr2 = &y; // point to y memory address
Console.WriteLine(x); // print 5
Console.WriteLine(y); // print 3
Console.WriteLine((int)ptr1); // print 5
Console.WriteLine((int)ptr2); // print 3
Console.WriteLine(*ptr1); // print 5
Console.WriteLine(*ptr2); // print 3
* char identify a pointer and & specify the memory address. But you should take care with pointers because unlike reference types, pointer types are not tracked by the default garbage collection mechanism.