I am working on a little project in c# in forms (visual studio) and I am having a problem.
I have the following code in my forms.cs:
private void Dierbutton_Click(object sender, EventArgs e)
{
string name = AnimalNameTextbox.Text;
bool fleshEater = CarnivoorCheckbox.Checked;
Animal.Sizes size;
if (AnimalSizeBig.Checked)
{
size = Animal.Sizes.Big;
}
else if (AnimalCheckboxMedium.Checked)
{
size = Animal.Sizes.Medium;
}
else if (AnimalCheckboxSmall.Checked)
{
size = Animal.Sizes.Small;
}
else
{
MessageBox.Show("Vul een grootte in!");
}
Animal newAnimal = new Animal(size, fleshEater, name);
allAnimals.Add(newAnimal);
DierListbox.Items.Add(newAnimal.Name);
}
And the following code in my Animal.cs class:
namespace Circustrein_algoritmic
{
public class Animal
{
public enum Sizes
{
None = 0,
Small = 1,
Medium = 3,
Big = 5
}
public Sizes Size;
public bool Flesheater { get; set; }
public string Name { get; set; }
/// <param name="size">Size</param>
/// <param name="flesheater">True of flase wanneer dier vleeseter is</param>
/// <param name="name">Name</param>
public Animal(Sizes size, bool flesheater, string name)
{
Size = size;
Flesheater = flesheater;
Name = name;
}
public string getType()
{
return Flesheater ? "Flesheater" : "Planteater";
}
}
}
I am getting the error "use of unassigned local variable 'size'" in this piece of code in the forms.cs
Animal newAnimal = new Animal(size, fleshEater, name);
But when I change the code to this:
Animal newAnimal = new Animal(Animal.Sizes.Big, fleshEater, name);
The error changes to the following warning: "The variable 'size' is assigned but its value is never used.
So it is assigned, but it is not at the same time????
I do not want to change the code to this:
Animal newAnimal = new Animal(Animal.Sizes.Big, fleshEater, name);
Because I don't want my size to be pinned to Big, Medium, Small or None.
I have no clue what to do.
Does anyone have any tips?
Thanks in advance!
So it is assigned, but it is not at the same time????
I understand that these compiler messages are confusing, and apologize for that.
The error messages that deal with definite assignment and the warnings which identify possibly wrong code were added piecemeal, over time, and without a solid plan to keep them consistent.
When I was on the compiler team I made several attempts to get them more consistent and more clear, but that work had mixed success to say the least. A detailed exegesis of all those attempts would take us far afield; I've written some articles and answers about those in the past; one of them that might interest you is this three part series.
The simple explanation is that the error and the warning are using "assigned" to mean two different things. The error message is:
use of unassigned local variable 'size'
but that's not quite right. What it should say is something like "local variable size is not definitely assigned a value on all possible control flows before it is read".
If you look at your code you'll see that if the final else is taken, then size is never written, but on that code path it is still read, and that's an error. There's no value there to read!
You then remove the read, and the error goes away, because it is not an error to fail to initialize a variable that is never read. However, the code now looks wrong; you did work to attempt to initialize size and then you never made use of that work, so that's probably a mistake. The warning:
The variable 'size' is assigned but its value is never used.
Is using "assigned" to mean "at some point in this method you assigned a value to this local variable, but then you never read from it, so why did you assign that value?"
This warning is not seen that often; the compiler usually suppresses it. Why? Because this pattern is extremely common:
int dummy = Blah();
// Note, dummy is never read, but I want to observe it in the debugger.
But in your code the compiler knows that you are probably not using size for the purposes of debugging; you've only assigned it constants. There's no mystery here about what its value is; you can just read the code and know what its exact value will be on every control flow.
So that's the difference: in the error, "unassigned" means "not definitely assigned on every control flow" and in the warning, "assigned" means "assigned at least once".
I have no clue what to do.
There are two ways to proceed.
First technique: keep the assignments the same, but avoid the code path that lacks the assignment at the time of read. For example:
else
{
MessageBox.Show("Vul een grootte in!");
return;
}
Now there is no problem; the only path on which size is not assigned returns before size is read.
Second technique: Add an assignment on all paths:
else
{
MessageBox.Show("Vul een grootte in!");
size = Animal.Sizes.None;
}
Now there is an assignment on every path before the read.
If you hit the else statement, no value is ever assigned to size; hence the compilation error.
Either intialise the variable when declaring, or assign a value in the else block.
Okay, so the reason it's saying "use of unassigned variable" is that there is a path through the code that it could take (in your first code snippet), where it might not be assigned -- that happens if it hits your final if block (where you print the message).
You can fix it either by assigning size a value inside THAT part of the method too, or you could insert a "return" after the MessageBox.show, so that it would simple drop out of the method at that point without creating an "Animal" at all (and therefore not passing an uninitialized size along).
In addition to what the others have posted, I wanted to note that the error switching to "size is assigned but never used" is not quite a conflict/opposite of "use of unassigned" - if you're sitting there scratching your head and saying "make your mind up - is it assigned or not?!" then you can look to the other answers for details on the first error:
"use of unassigned" means "there are some possible paths in your code where this variable might not be assigned a value before it's used"; you can read a lot of tech info on this by googling for "c# definite assignemnt"
and the second error - "assigned but never used" basically means "size only ever appears on the left hand side of an =", so it's detecting that you assign a value to it, but then you don't ever actually make use of it
As you can imagine, the two aren't in conflict - it's possible to have a situation where you use a variable that might not have a value, and if you take that use away you're only left with code paths that assign a value but don't use it
Related
This is a longshot but...
I understand there is a way to tell if variable A (var1, var2...., varX) points to instance of class by using Equals:
List<string> _mainInstance = new();
var var1 = _mainInstance;
var var2 = _mainInstance;
var var3 = _mainInstance;
//I understand how to tell if variable points to _mainInstance
if (var1.Equals(_mainInstance))
{
//It does because it points by reference
}
//I want to check if any variable still point to _mainInstance
if (!_mainInstance.HasOthersPointingToIt())
{
//Safe to delete _mainInstance
}
I don't know at design time how many pointers to _myInstance there will be. I want to check if my _mainInstance has any variables still pointing to it every so often. I thought maybe reflection or garbage collection but all my research there is coming up with nothing.
Is there a way to examine a variable (in this case an instance of a class) and tell if anything else (variables, properties of a class instance) still point to it?
Edit:
#GuruStron asks what is the underlying problem I am trying to solve?
Answer: I have a parent/child "tree" that I need to keep track of. That in itself is pretty easy. My difficulty is that the tree has blocks that have a single definition and that definition gets reused.
In the graph below it shows the top tree with stars. The stars represents pointers to block definitions. Below that on the left are the actual block definitions.
The the block definition gets substituted and the final tree looks like this:
When a block pointer is deleted I need to make sure that nothing else is pointing to that block definition and delete the block definition when it is no longer needed.
I am trying to do what seems simple to me, but can't manage to implement it. I want to increment a simple variable in a Data flow Task...
The variable is set in the ReadWriteVariables, there is no output nor input columns.
This is the end-goal (I'll avoid sharing the monstrosity my current code is) :
public class ScriptMain : UserComponent
{
public override void PostExecute()
{
base.PostExecute();
Variables.intDatasourceUpdated++;
}
}
I suppose I'm missing something (very junior with C# and .Net), so any help would be appreciated.
Edit:
I want to increment my "updated" or my "inserted" variables depending on the lookup : lookup printscreen. Here, it is always "updated".
My error is : error printscreen. Note that it says "at Variables.get_intDatasourceInserted()" but I never go to that branch here. So I commented the increment line in the "insert script" and it worked.
But then, when I'll have the "insert" case, as I currently have it deactivated, it won't increment.
"The collection of variables locked for read and write access is not available outside of PostExecute".
You are posting your "Update" snippet, the error is saying you are trying to update intDatasourceInserted which likely in your "Insert"s PreExecute(). Which isn't allowed.
In either case you'll still have an issue, since each task there execute simultaneously, waiting for pipeline data, and variables don't work well between tasks inside one data flow, you'll probably need to mangle the data itself as it flows or access the altered variable outside the data flow in the control flow.
You need to decalre the variable outside of row processing.
public int counter = 0;
public void main()
{
counter++;
}
And at the end set the variable to counter.
post execute...
Variables.Counter = counter;
Usually this can be done, by defining a new C# variable. Set the value of the SSIS-variable to the new variable and then back again.
// Declare user-defined variable and increase the value by 1
int variableValue = Convert.ToInt32(Dts.Variables["myVariable"].Value);
variableValue++;
// Write the new value back into the variable
Dts.Variables["myVariable"].Value = variableValue;
I want to know the consequence of using a class level variable across different functions in a multi-threaded app.
I am creating a class variable and sharing it across get and set function.
The variable is bound to have a value like :
"testuser-2.3" {username-projectversion}
Code:
class Test()
{
private string key;
public Get(string something)
{
key = setToSOmething();
}
public Set(string something)
{
key = setToSOmething();
}
}
Is this code prone to fail in multithreaded environments? Like if two users are accessing diffrent versions of the project, will the "key" value will be diffrent at any random given point?
Thanks in advance.
I want to know the consequence of using a class level variable across different functions in a multi-threaded app.
What you're doing in your code will work, sort of, but it doesn't demonstrate the consequence of allowing multiple threads to modify a variable. It doesn't answer your question. It just means that you'll be okay with the particular thing you're doing with this particular variable.
In this case you're just assigning a different reference to your string variable. That's safe, in a way. You won't get any mangled strings, but it means that you don't know which string a given function will get when it reads the variable. In some scenarios that's not so bad, but it's a little chaotic.
The problem occurs when multiple threads interact with your variable in a way that isn't thread safe.
Here's a really simple test method I wrote without actually knowing what was going to happen:
public class MultithreadedStringTest
{
private string _sharedString;
[TestMethod]
public void DoesntMessUpStrings()
{
var inputStrings = "The quick fox jumped over the lazy brown dog".Split(' ');
var random= new Random();
Parallel.ForEach(Enumerable.Range(0, 1000), x =>
{
_sharedString += " " + inputStrings[random.Next(0, 9)];
});
var outputStrings = _sharedString.Trim().Split(' ');
var nonMangledStrings = outputStrings.Count(s => inputStrings.Contains(s));
Assert.AreEqual(1000, outputStrings.Length,
$"We lost {1000-outputStrings.Length} strings!");
Assert.AreEqual(nonMangledStrings, outputStrings.Length,
$"{outputStrings.Length-nonMangledStrings} strings got mangled.");
}
}
I'm starting with 10 words, and then, in a Parallel.Each loop appending 1000 words selected from those 10 to a single string from concurrent threads.
I expected the string to get mangled. It didn't. Instead what happened is that out of my 1000 words that I added, typically a few hundred just got lost.
We lost 495 strings!
Obviously that's not the particular operation that you're performing. But what it shows is that when we perform concurrent operations, we need to know that we're either calling a thread safe method or we're using some mechanism to prevent conflicts. We want to know how our code will behave and not cross our fingers and hope for the best.
If we're not careful with it the results will be unpredictable and inconsistent. It might work when you test it and fail later, and when it does it will be difficult to diagnose because you won't be able to see it happen.
Leaving aside the fact that Get and Set are both setting key in your code...
This code won't be prone to failure because of the nature of string. It's an immutable class, and the data is basically constructed elsewhere, and then your key assignment happens, as a single, atomic operation. (It's a reference or basically a pointer assignment).
So...even if you were to have two setters, key will always reference a valid string. Depending on the use of this code, though, the order in which the assignments actually happen could be counterintuitive. Say your get actually returns the string...set(get() + "X") could eventually lose Xes if called multiple times from multiple threads. Because all the get calls could get the same old string and perform the string addition on that. But this is you assuming set AND get together are an atomic operation. The accepted answer here:
reference assignment is atomic so why is Interlocked.Exchange(ref Object, Object) needed?
explains this better than I'm doing.
The contrary example would be if you were to use StringBuilder and actually modify the data inside the class...that would not be thread-safe and would certainly require a lock.
Updating answer to explain my reasoning behind my argument that the OP's code is fundamentally thread-safe considered on its own. Consider the following code which attempts to add thread-safety:
public partial class MainWindow : Window
{
private object emergencyLock = new object();
private string _status;
public string status
{
get
{
//make sure if an emergency is happening we get the best possible string.
lock (emergencyLock)
{
return _status;
}
}
set
{
//we could also lock here instead of in GetEmergencyString()..which would fix the get+set=atomic issue
_status = value;
}
}
private string GetEmergencyString()
{
//this function understands an emergency is happening
lock (emergencyLock)
{
//Maybe I'm fetching this string from a database, or building it by hand
//It takes a while...We'll simulate this here
Thread.Sleep(1000);
return "Oh crap, emergency!";
}
}
private void Normal_Button_Click(object sender, RoutedEventArgs e)
{
status = "Nothing much going on.";
}
private void Emergency_Button_Click(object sender, RoutedEventArgs e)
{
//GetEmergencyString() is evaluated first..finally returns a string,
//and THEN the assignment occurs as a single operation
status = GetEmergencyString();
}
}
I'll make the following points about this code:
It does prevent a status seeker from getting a "boring" status during an emergency. It also potentially forces the status seeker to wait a full second before getting that status...Effectively solving nothing, most likely.
Also consider that even single-threaded, there's a fundamental issue here. The fundamental issue is NOT thread safety (in my opinion). The fundamental issue is delay. Better solutions? Fixing the delay. Active notification of the new state..Events, pubsub, etc. A state machine. Even a volatile bool IsEmergency is much better than the "thread-safety" I've added. Any active, intelligent logic in the code. Maybe you don't want the emergency state to be overwritten by the normal state? Again...not a threading issue.
I have many scenarios during my development where I want to do something such as
try
{
long presult = EvalInner(eqtn,new Tuple<int, int>(++begidx,curidx-1),eqtnArgs);
}
catch ( Exception e )
{
throw e;
}
result = evalNewResult(result,lastop,presult,ref negateNextNum,ref negateNextOp);
// ...
return presult;
but then my compiler flags the presult on the line
result = evalNewResult(result,lastop,presult,ref negateNextNum,ref negateNextOp);
saying
The name 'presult' does not exist in the current context
If it were smart, it would understand that presult is either initialized in the try block, or the procedure is exited before presult is ever used.
Possible workarounds (none of them good):
Declare long presult; right before the try statement. This makes the compiler mad because it wrongly thinks there's a possibility of returning an unintialized variable.
Initialize it with long presult = default(long). This works, but it's bad practice because someone reading the code doesn't know whether intializing it to the default value is to work around the problem described in 1. or is because the value presult because set to the default long has some real meaning in the context of the program.
Initialize it with long? presult = null. This is semantically better because it's clear that it means "presult is meant to have no value at this point" whereas in 2. the reader has to figure out that presult has a meaningless value. The problem here is that, not only does it take extra memory to nullify a value, but I then have to change the function EvalInner to return a long? and this results in a chain of needing to change many more longs to long?s and my program ends up splattered with nullified variables; it's a complete mess of question marks haha.
Anyways, how should I be handling a case like this?
I'll go over your points one by one:
Declare long presult; right before the try statement. This makes the
compiler mad because it wrongly thinks there's a possibility of
returning an unintialized variable.
Actually, the compiler correctly determines that there is the possibility of returning an uninitialized variable. Since the variable is only set if the function on the right hand side succeeds, and since you have it in a try..catch block then there is the possibility that the function may throw and not return, therefore not initializing the variable. What the compiler is not smart enough to see is that you are catching the top level exception and throwing (in a bad way, losing the stack trace) and it should not reach the return. However there are ways to get around that (mostly during debug by dragging the execution cursor).
Initialize it with long presult = default(long). This works, but
it's bad practice because someone reading the code doesn't know
whether intializing it to the default value is to work around the
problem described in 1. or is because the value presult because set
to the default long has some real meaning in the context of the
program.
Since value types like long, int, short etc must have a value, this is not bad practice. If you want to represent them as not having a value, use the nullable versions of those types (i.e. long? presult = null).
Initialize it with long? presult = null. This is semantically better
because it's clear that it means "presult is meant to have no value
at this point" whereas in 2. the reader has to figure out that
presult has a meaningless value. The problem here is that, not only
does it take extra memory to nullify a value, but I then have to
change the function EvalInner to return a long? and this results in
a chain of needing to change many more longs to long?s and my
program ends up splattered with nullified variables; it's a complete
mess of question marks haha.
Again, the function must return a value that is a valid long, so if you want to return something that can easily be identified as an incorrect value, then return the nullable version, otherwise you have to return a valid value. Only float and double have NaN members...
Another option would be some kind of TryXXX method, where the return value is a boolean and you use an out long as a parameter to store the result.
I don't understand you problem. The compiler can't know the value of presult when you call evalNewResult that's why you need to declare it outside the try block. It's a general rule of scopes in C# and a lot of other languages.
The solution is to declare and initialize it before the try block. The question is "what value should presult have in case an exception occurs". The compiler can't ask this question himslef.
How about:
try
{
long presult = EvalInner(eqtn,new Tuple<int, int>(++begidx,curidx-1),eqtnArgs);
result = evalNewResult(result,lastop,presult,ref negateNextNum,ref negateNextOp);
// ...
return presult;
}
catch ( Exception e )
{
//Do some useful logging
throw; //Don't lose stacktrace!
}
Please check this link for more enlightment
Compilers are in the business of generating code which manages the storage of the data manipulated by that program. There are lots of different ways of generating code to manage memory, but over time two basic techniques have become entrenched.
The first is to have some sort of "long lived" storage area where the "lifetime" of each byte in the storage -- that is, the period of time when it is validly associated with some program variable -- cannot be easily predicted ahead of time. The compiler generates calls into a "heap manager" that knows how to dynamically allocate storage when it is needed and reclaim it when it is no longer needed.
The second is to have some sort of "short lived" storage area where the lifetime of each byte in the storage is well known, and, in particular, lifetimes of storages follow a "nesting" pattern. That is, the allocation of the longest-lived of the short-lived variables strictly overlaps the allocations of shorter-lived variables that come after it.
Local variables follow the latter pattern; when a method is entered, its local variables come alive. When that method calls another method, the new method's local variables come alive. They'll be dead before the first method's local variables are dead. The relative order of the beginnings and endings of lifetimes of storages associated with local variables can be worked out ahead of time.
For this reason, local variables are usually generated as storage on a "stack" data structure, because a stack has the property that the first thing pushed on it is going to be the last thing popped off.
So overall local variable are are short lived and usually stored in stack, why stack coz its efficient than others. Link for more info why stack
Why doesn't my C# compiler (Visual Studio) let me do this with a try block?
That is because braces define a scope. From Variable and Method Scope in Microsoft .NET:
If you declare a variable within a block construct such as an If statement, that variable's scope is only until the end of the block. The lifetime is until the procedure ends.
how should I be handling a case like this?
Go for option 1.
This makes the compiler mad because it wrongly thinks there's a possibility of returning an unintialized variable
Option 1 does not make the compiler mad. The compiler is always right :-)
I created the following SSCCE and it absolutely works:
using System;
namespace app1
{
class Program
{
static void Main(string[] args)
{
Presult();
}
private static long Presult()
{
long presult;
try
{
object eqtn = null;
char begidx = '\0';
int curidx = 0;
object eqtnArgs = null;
presult = EvalInner(eqtn, new Tuple<int, int>(++begidx, curidx - 1), eqtnArgs);
}
catch (Exception e)
{
throw e;
}
int result = 0;
object lastop = null;
object negateNextNum = null;
object negateNextOp = null;
result = evalNewResult(result, lastop, presult, ref negateNextNum, ref negateNextOp);
// ...
return presult;
}
private static int evalNewResult(int result, object lastop, long presult, ref object negateNextNum, ref object negateNextOp)
{
return 0;
}
private static long EvalInner(object eqtn, Tuple<int, int> tuple, object eqtnArgs)
{
return 0;
}
}
}
how should I be handling a case like this?
The correct way is your Option 1. That doesn't make compiler "mad", because in fact declaring a variable and initializing it later is allowed construct (not only for this particular case) from the very beginning, and compiler should be able to handle it correctly w/o problem.
IMO, the only drawback (or better say inconvenience) is that the keyword var cannot be used, so the type must be specified explicitly. But some people that are against using var in general would say this is indeed a good thing :-)
I'm still relatively new to C# and the answer to this is probably pretty obvious, but I'm struggling to solve it
I have an enum defined as follows:
enum Request {
None = 0,
GetData,
SendData,
some other values...
};
I then have two variables both defined as type Request as follows
Request currentRequest; // This is a class member variable
Request request; // This is a local variable within a method.
The first variable is assigned using currentRequest = Request.GetData;
The second local variable request is assigned using request = (Request)data, where data is byte of value 1 (as the value is being decoded from a buffer of USB data being received). I don't know if this is relevant but mention it just in case.
I want to compare them within the method in which the second variable is declared, I originally did it like this:
if(request != currentRequest)
{
// Throw an exception
}
This works most of the time, but occaisionally the exception is thrown because the two values don't equate, however when I check them in the debugger they are both equal to Request.GetData. This got me thinking that the variables may be pointers to objects rather than values so I tried also using...
!request.Equals(currentRequest)
and
request.CompareTo(currentRequest)!=0
and similarly both of these work most of the time but occaisionally fail even though when the values are checked in the debugger they are both Request.GetData.
What's really confused me is that it works most of the time, just fails occaisionally - I'd expect it to either work or not work consistently.
Any ideas?
No, if the variables are genuinely of type Request then that's a value type, and using == should be absolutely fine.
I suspect that the debugger is showing you something slightly odd. I suggest you make the exception include both request and currentRequest to show you what's going on.