How to limit scope of a constant to method/block - c#

Is there any way to limit the scope of a compile-time constant to a method/block of code that avoids hardcoding the value?
Something like the following:
public int SomeMethod(int a) {
const int SomeCompileTimeConstant = 10; // obviously this doesn't exist
return a + SomeCompileTimeConstant;
}
opposed to hardcoding the value:
public int SomeMethod(int a) {
return a + 10;
}
or making it a class-level constant:
public class A {
private const int SomeCompileTimeConstant = 10;
public int SomeMethod(int a) {
return a + SomeCompileTimeConstant;
}
}

You can declare a constant inside a function.
When you wrote
public int SomeMethod(int a) {
const int SomeCompileTimeConstant = 10; // obviously this doesn't exist
return a + SomeCompileTimeConstant;
}
you were wrong.

Related

How to add a second argument(Number) to a calculator program?

I'm working on a small calculator program in Unity.
I only need the calculator to work with two numbers.
The feature I'm trying to implement:
After inputting the math operator, It should display the second number in the third index.
The issue:
Instead of Adding a second number, the first number is being overwritten if a different number is pressed on the keyboard.
Here's the script I've created:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Functions : MonoBehaviour
{
// Global Variable to display text on top panel
public Text panelText;
// Create a number variable
string num;
string num1;
string num2;
string mOpr;
string calNum;
string cbutton;
string opr;
bool isFirstNum;
// Start is called before the first frame update
void Start()
{
}
// A function with an int argument
public void NumberInputOne(string num)
{
num1 = num;
num2 = num;
if (panelText.text.Length < 1)
{
Debug.Log(num1);
panelText.text = num1;
isFirstNum = false;
}
else if (panelText.text.Length > 1 && panelText.text.Length < 3)
{
num2 = num;
Debug.Log(num2);
panelText.text = num1 + mOpr + num2;
}
}
public void OperatorInput(string opr)
{
mOpr = opr;
if (panelText.text.Length > 0 && panelText.text.Length < 2)
{
panelText.text = num1 + mOpr;
}
}
// public void NumberInputTwo(int num)
//{
// ResNum2 = num;
// Debug.Log(ResNum2);
// if (panelText.text.Length > 1 && panelText.text.Length < 3)
// {
// panelText.text = ResNum1 + opr + ResNum2;
// }
// }
public void RestartCal(string cButton)
{
panelText.text = "";
}
}
I've also added a screen recording to capture the issue:
First number being overwritten
Do you have any suggestions?
Thank you
use the NumberInputOne func like below;
public void NumberInputOne(string num)
{
if (num1 is null)
{
Debug.Log(num1);
panelText.text = num1;
num1 = num
}
else
{
num2 = num;
Debug.Log(num2);
panelText.text = num1 + mOpr + num2;
}
}
btw i recommend that you review the sample calculation application codes. because apart from what you're asking, there are places you need to improve in general.
This feels like a beginner programming exercise. But the right way to build a calculator involves programming concepts that you probably haven't been taught yet. Which makes this a poor choice as an assignment.
Personally I would build a calculator by defining a simple syntax tree to represent the formula being input. Including methods to display the formula and calculate the answer. For example;
public interface IValue
{
int Calculate();
string PrintValue();
}
public class Number : IValue
{
public int? Value;
public void AddDigit(int digit) => Value = (Value ?? 0) * 10 + digit;
public int Calculate() => Value ?? 0;
public string PrintValue() => Value?.ToString();
}
public abstract class BinaryOperator : IValue
{
public IValue Left;
public IValue Right;
public abstract int Operation(int left, int right);
public abstract char Operator { get; }
public int Calculate()
{
var left = Left.Calculate();
var right = Right.Calculate();
return Operation(left, right);
}
public string PrintValue() => $"{Left?.PrintValue()} {Operator} {Right?.PrintValue()}";
}
public class Addition : BinaryOperator
{
public override char Operator => '+';
public override int Operation(int left, int right) => left + right;
}
// TODO define other operators
Then think about how each button should change the syntax tree.
// the entire formula
public IValue Root;
// the number currently being typed
public Number Input;
public void Display() {
panelText.text = Root.PrintValue();
}
// start / clear
public void Start(){
Root = Input = new Number(){
Value = 0
};
Display();
}
public void Plus(){
// left as an exercise for the reader
Display();
}
public void Digit(int digit) {
Input.AddDigit(digit);
Display();
}
public void Calculate() {
// left as an exercise for the reader
Display();
}

Assigning to a variable by reference?

Thanks to the kind folks who answered my previous question from a few days ago, I now know how to pass arguments by reference:
static void Main()
{
int i = 0;
Add(ref i, 100);
// now i == 100
}
static void Add(ref int arg, int increment)
{
arg += increment;
}
But is there a way for me not to just pass i by reference, but actually store its location in another variable? By that I mean use i like I did in my example; affecting the original instance, but in a way that's permanently linked and not leaving scope.
I vaguely know that I could use a pointer to determine the location in unsafe context but I was wondering if I could do this without any of that, or if it is just recommended to use the unsafe method.
If you are using C# 7 you can use ref local and ref return to store an updateable reference to any field.
In this example I change the private field _privateField from 0 to 100 from outside Foo, the class in which it is defined, by returning it as a ref int and updating it by reference.
class Foo
{
private int _privateField = 0;
public ref int GetReference()
{
return ref _privateField;
}
public override string ToString()
{
return _privateField.ToString();
}
}
public class Program
{
public static void Main()
{
var foo = new Foo();
var referenceToPrivateField = foo.GetReference();
referenceToPrivateField = 100;
Console.WriteLine(foo);
}
}
Prior to that, you'd have to store the value in a field contained in an object, and pass around a reference to the object instead.
In this example I change the value from 0 to 100 from outside Foo, even though it is stored (indirectly) in a field that is private inside the Foo instance.
class ValueTypeReference<T> where T : struct
{
public T Value { get; set; }
}
class Foo
{
private ValueTypeReference<int> _privateField = new ValueTypeReference<int>{ Value = 0 };
public ValueTypeReference<int> GetReference()
{
return _privateField;
}
public override string ToString()
{
return _privateField.Value.ToString();
}
}
public class Program
{
public static void Main()
{
var foo = new Foo();
var referenceToPrivateField = foo.GetReference();
referenceToPrivateField.Value = 100;
Console.WriteLine(foo);
}
}
Output:
100
Well, if I udnerstood you correctly, you want the variable to have global scope, which can be achieved by putting variable as class field/property:
class Program
{
private static int _i;
static void Main()
{
_i = 0;
Add(100);
// now _i == 100
}
static void Add(int increment)
{
_i += 100;
}
}

Are value type variables declared in local function stack-allocated?

I was reading about local functions introduced recently and started to wonder about the question. Afaik local variables of value types in lambdas are allocated in the heap. Also there was something that local function have advantage over lambdas when capturing value types, which do not require in this case additional heap allocation. Still following is not clear to me:
Are local value type variables declared in local functions allocated on stack?
What about value type variables, that are declared in "parent" function and captured in local function?
(provided that parent is not anonymous itself).
edit:
int ParentFunction ()
{
int parentVarLambda = 0;
int parentVarLocal = 0;
Func<int> lamdaFuncion = () => parentVarLambda + 1;
int a = lamdaFuncion();
int b = LocalFunction();
return a + b;
int LocalFunction()
{
int localFuncVar = 1;
return parentVarLocal += localFuncVar ;
}
}
where will be parentVarLambda, parentVarLocal and localFuncVar allocated?
None of it is heap-allocated, unless something else is going on (particularly if the compiler can't guarantee that the lifetime of variables captured by the local function don't exceed the lifetime of the parent method, e.g. if a delegate refers to the local function, or the local function contains yield return or await statements).
Let's say you have:
public void M(int i) {
Inner(i + 1);
void Inner(int x)
{
int j = x + i;
Console.WriteLine(j);
}
}
Using the wonderful SharpLab, we can see this gets compiled to:
[StructLayout(LayoutKind.Auto)]
[CompilerGenerated]
private struct <>c__DisplayClass0_0
{
public int i;
}
public void M(int i)
{
<>c__DisplayClass0_0 <>c__DisplayClass0_ = default(<>c__DisplayClass0_0);
<>c__DisplayClass0_.i = i;
<M>g__Inner|0_0(<>c__DisplayClass0_.i + 1, ref <>c__DisplayClass0_);
}
[CompilerGenerated]
internal static void <M>g__Inner|0_0(int x, ref <>c__DisplayClass0_0 P_1)
{
Console.WriteLine(x + P_1.i);
}
So the compiler's taken our inner function, and rewritten it as a static method. Parameters to the inner function remain as parameters to the static method. Things captured by the inner function end up as fields on a compiler-generated struct, which is passed by ref (to avoid copying, and so that changes made to it in the static method are reflected in the calling method).
Structs allocated in that inner function will just be allocated the same in the static method - i.e. on the stack.
Now let's compare that to equivalent code, but using a delegate:
public void M(int i) {
Action<int> inner = x =>
{
int j = x + i;
Console.WriteLine(j);
};
inner(i + 1);
}
This gets compiled to:
[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
public int i;
internal void <M>b__0(int x)
{
Console.WriteLine(x + i);
}
}
public void M(int i)
{
<>c__DisplayClass0_0 <>c__DisplayClass0_ = new <>c__DisplayClass0_0();
<>c__DisplayClass0_.i = i;
new Action<int>(<>c__DisplayClass0_.<M>b__0)(<>c__DisplayClass0_.i + 1);
}
Here we can see the difference. The compiler's generated a new class, which has fields to hold the variables captured by the delegate, and has a method on it which contains the body of our delegate. It's had to use a class, rather than a struct passed by reference.
To understand why, think about the fact that your code can pass a delegate around - it could store it in a field, or return it, or pass it to another method. In that case, it's not just being synchronously called by its parent (as a local function must be), but it has to instead carry around the variables it captured with it.
Note that something similar happens if we create a delegate referring to a local function:
public void M(int i) {
void Inner(int x)
{
int j = x + i;
Console.WriteLine(j);
}
Action<int> inner = Inner;
inner(i + 1);
}
This gets compiled to the same as before:
[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
public int i;
internal void <M>g__Inner|0(int x)
{
Console.WriteLine(x + i);
}
}
public void M(int i)
{
<>c__DisplayClass0_0 <>c__DisplayClass0_ = new <>c__DisplayClass0_0();
<>c__DisplayClass0_.i = i;
new Action<int>(<>c__DisplayClass0_.<M>g__Inner|0)(<>c__DisplayClass0_.i + 1);
}
Here, the compiler's spotted that it needs to create the delegate anyway, so it generates the same code as in the previous example.
Note that there are other cases where the compiler has to perform heap allocations when calling a local function, such as if the local function has to be resumable because it contains yield return or await statements.
To address the specific example in your edit:
int ParentFunction ()
{
int parentVarLambda = 0;
int parentVarLocal = 0;
Func<int> lamdaFuncion = () => parentVarLambda + 1;
int a = lamdaFuncion();
int b = LocalFunction();
return a + b;
int LocalFunction()
{
int localVar = 1;
return parentVarLocal += localVar;
}
}
We can again put this into SharpLab, and get:
[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
public int parentVarLambda;
public int parentVarLocal;
internal int <ParentFunction>b__0()
{
return parentVarLambda + 1;
}
internal int <ParentFunction>g__LocalFunction|1()
{
int num = 1;
return parentVarLocal += num;
}
}
private int ParentFunction()
{
<>c__DisplayClass0_0 <>c__DisplayClass0_ = new <>c__DisplayClass0_0();
<>c__DisplayClass0_.parentVarLambda = 0;
<>c__DisplayClass0_.parentVarLocal = 0;
int num = new Func<int>(<>c__DisplayClass0_.<ParentFunction>b__0)();
int num2 = <>c__DisplayClass0_.<ParentFunction>g__LocalFunction|1();
return num + num2;
}
Note that the compiler's realised that it had to create a new instance of a generated class for the delegate anyway, so it's just opted to deal with the local function in the same way at no extra cost. It doesn't make much difference in this case, but this technique is needed where the delegate and the local function capture the same variables - they need to be hoisted into the same generated class.
Because of this, both parentVarLambda and parentVarLocal were allocated on the same compiler-generated class, and localFuncVar just got optimized away (but would have been allocated on the stack in <ParentFunction>g__LocalFunction|1()).

Override objects return value

I'm trying to compare an object with an int value such as
if (myObject - 5 == 0)
doSomething();
my class could look something like this: (most setters/getters removed, so don't mind that all variables are private)
public class SomeClass
{
public string name;
private int minValue;
private int maxValue;
private int currValue;
public int getCurrentValue()
{
return currValue;
}
}
What I'm trying to achieve is something like this:
someClassInstance - 5;
to be equal
someClassInstance.getCurrentValue() - 5;
Can I make an override for the object to act as an int (it's own variable) opposed to just being an object?
May be operator is the case?
public class SomeClass {
...
public static int operator -(SomeClass left, int right) {
if (Object.ReferenceEquals(null, left))
throw new ArgumentNullException("left");
return left.getCurrentValue() - right;
}
}
...
SomeClass someClassInstance = new SomeClass(...);
int result = someClassInstance - 5;
Another possibility (based on implicit operator) is to convert SomeClass implicitly to int whenever required:
public class SomeClass {
...
// Whenever int is requiered, but SomeClass exists make a conversion
public static implicit operator int(SomeClass value) {
if (Object.ReferenceEquals(null, value))
throw new ArgumentNullException("value");
return value.getCurrentValue();
}
}
...
SomeClass someClassInstance = new SomeClass(...);
int result = someClassInstance - 5;
Actually you would be much better off overriding operator int, that way you can do far more calculations with less overloads:
using System;
namespace Demo
{
public class SomeClass
{
public string name;
private int minValue;
private int maxValue;
public int currValue;
public int getCurrentValue()
{
return currValue;
}
public static implicit operator int(SomeClass value)
{
if (value == null)
throw new ArgumentNullException("value");
return value.currValue;
}
}
internal class Program
{
private void run()
{
var test = new SomeClass {currValue = 5};
if (test - 5 == 0)
Console.WriteLine("It worked");
if (test + 5 == 10)
Console.WriteLine("This also worked");
}
private static void Main()
{
new Program().run();
}
}
}
You could experiment with a mixture of implicit conversions and operator overloading, but from my experience you will never make it work as seamlessly as you wish (and as you could get it to work in C++).
If I were you, I would change the getCurrentValue to a property:
public int CurrentValue
{
get {return currValue};
}
and just use someClassInstance.CurrentValue -5

how can i modify a value in list<t>?

class SomeClass
{
private struct PhraseInfo
{
public int Start;
public int Length;
}
...
private void SomeMethod(...)
{
List<PhraseInfo> posesBracket = new List<PhraseInfo>();
posesBracket.Add(new PhraseInfo());
posesBracket[0].Start = 10;
}
of cause, posesBracket[0].start=10; occur compiler error CS1612 : "Cannot modify the return value of 'expression' because it is not a variable"
how can i modify a value in list?
The problem is that PhraseInfo is a value type, so the this[] method will return a value, not a reference, to solve it, do this:
PhraseInfo pi = posesBracket[0];
pi.Start = 10;
posesBracket[0] = pi;
var temp = posesBracket[0];
temp.Start = 10;
posesBracket[0] = temp;
You cannot have a struct defined as a method. And as they say, you need the reference to change values. So it goes like this:
class SomeClass
{
private struct PhraseInfo
{
public int Start;
public int Length;
}
private void somemethod()
{
List<PhraseInfo> posesBracket = new List<PhraseInfo>();
posesBracket.Add(new PhraseInfo());
PhraseInfo pi = posesBracket[0];
pi.Start = 10;
posesBracket[0] = pi;
}
}

Categories

Resources