Sorry for this noob question, but I could not find the info anywhere
I see many functions or constructor creating a task and assigning it to an undefined underscore variable
public SomeClass()
{
_ = SomeTaskAsync();
I don't understand what does this do
is it a temp variable ? or something to avoid gc to do its job ?
thanks
[edit: sorry but I don't understand the point of using a variable if it is not used, underscore or not]
Superficially, _ discards intentionally an unused variable in the application code.
To dive into this
https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/discards
Related
This question already has answers here:
Case Statement Block Level Declaration Space in C#
(6 answers)
Closed 12 months ago.
Found this construction while reviewing some code and I was expecting it to not compile at all, tbh. Any reasons why this is permitted?
int i = 0;
switch (i)
{
case 0:
int k = 0;
break;
case 1:
k = 1;
break;
}
Edit: even more strange, adding Console.Out.WriteLine(k); after case 1: gives error use of unassigned variable 'k'...
Any reasons why this is permitted?
We probably cannot say for certain: The essential answer is "because it is" or "because your reasons for thinking it shouldn't be differ with the thinking of those who designed the language" but we can't really speak to questions like "what were Microsoft thinking when they designed it such that...", unless perhaps someone is one of the privileged few to have sat in that design meeting and can be authoritative
SharpLab.io will, however, tell you what happens under the hood; it compiles then decompiles your code and shows you the result, so you can get an idea of what your code was transformed into by the compiler:
Note: swapped your numbers for other, non-default, ones so that identification of what was what can be maintained after the compiler changes the names
A lot of the code you write is syntactic sugar for something else; here you can see your int k isn't buried within the switch, scoped to only "within the first case", but transformed into something else entirely.. It's thus legal C# because nothing prevents it not being, and you can rationalize that in a way that will help you remember it.. In a similar way, perhaps this looks like it shouldn't work:
object o = "";
if(o is string s){
}
s = "";
s looks, to me, like it's created within the scope of the if, yet it's accessible outside the if.. You'll find a similar explanatory transformation if you run that through SharpLab..
I can't find an answer to my problem. In dotNet/C#, is it possible to check if a variable was declared to some type and if not, declare it?
Thanks
[Edit] In this case, C# is used as a preexecute language in Open Text CMS. C# code can be used in any module. Using a non-declared variable throws hard to debug errors, as does double-declaring a variable. That's why I'd like to check.
[Edit2] Yes it is most probably compiled somewhere, but the errors are thrown (or rather not thrown) on runtime
[Edit3] Further explanation:
In Open Text, every page can hold several modules, several instances of a module and the same instance of a module several times. In each module, you can use C# as a "pre-execute" language. This is mostly really easy scripting to maneuver around the failings of OpenText. You introduce small variables, set them to true or false, and three lines later write a condition based on the variable. We could (and do) declare a bunch of variables in an initialization block of the page, but since there are so many, it would help to be able to check if a variable was declared and if not, declare it.
I like the idea of changing this to a key/value dictionary but this is a really large site with loads of pages/modules and instances and I'm looking for a working solution without changing the whole thing.
The actual code is really simple most oft he time:
var hasHeadline = false; // this will throw an error if hasHeadline was declared before
hasHeadline = true; // if some CMS condition is met. this will throw an error if hasHeadline wasn't declared
if(hasHeadline) { ** CMS code ** }
As I said, this will show up in multiple instances over which I don't have full control. The resulting "error" will be that the whole code block is stripped from the page.
Declare a single variable that is dynamic, e.g. an ExpandoObject.
dynamic Globals = new ExpandoObject();
Use this variable to store all of your global state.
Globals.hasHeadline = false; //No declaration needed, so
Globals.hasHeadline = true; //no chance of a duplicate declaration
There's no need to. C# is a statically typed programming language ("type" refers to more than just class, struct, and interface: "static typing" means the "types" (shapes) of data, objects and values in your program are known
statically - i.e. at compile-time). If something isn't declared in scope then your code simply won't compile.
This also applies to locals (local variables, method parameters, etc).
This won't compile:
class Foo
{
void Foo( String x )
{
if( z > 0 ) { // `z` isn't declared as a field, parameter or local.
// ...
}
}
}
Similarly, this won't compile:
class Foo
{
public string x;
}
class Bar
{
void Baz( Foo foo )
{
if( foo.z > 0 ) { // `z` is not declared in `Foo`
}
}
}
That said, there are some things you do need to check-before-using in C#, such as:
Nullable references or nullable values.
Entries in a Dictionary or other keyed collection.
Type-checking when you want a known subclass or interface (As C# still does not natively support algebraic types, grrrr)
...but none of those involve checking for declarations.
In VB.NET you can use an object initializer and reference the same members on the right hand side, like this:
GetValue.Add(New ArrayIndexInfo() With {
.Type = CType(NvpInfo(Index), Type),
.Name = NvpInfo(Index + 2).ToString,
.NvpValues = CType(.Type.GetField(NvpInfo(Index + 1).ToString).GetValue(Instances.First(Function(o) o IsNot Nothing AndAlso o.GetType = CType(NvpInfo(Index), Type))), NameValuePair())
})
Notice how in the line that sets .NvpValues you can reference .Type and that it's no problem.
But if you try to do that in c# (or like I did, try to convert a project from vb.net to c#), you get an error.
<variable> is not declared
I worked around it like this, which is not DRY because ((Type)NvpInfo[Index]) is repeated:
functionReturnValue.Add(new ArrayIndexInfo {
Type = (Type)NvpInfo[Index],
Name = NvpInfo[Index + 2].ToString(),
NvpValues = (NameValuePair[])((Type)NvpInfo[Index]).GetField(NvpInfo[Index + 1].ToString()).GetValue(Instances.First(o => o != null && o.GetType() == (Type)NvpInfo[Index]))
});
Why doesn't c# allow this? I think it should. I think converting legacy code to c# should be as painless as possible.
Is there a better way that I get around this and still use the object initializer?
To answer the question, I'll base myself on a simplified version of your example
VB.NET:
Dim c = New SomeClass With {
.Prop1 = "abc",
.Prop2 = .Prop1
}
Console.WriteLine(c.Prop1) 'prints "abc"
Console.WriteLine(c.Prop2) 'prints "abc"
C#
var c = new SomeClass
{
Prop1 = "abc",
Prop2 = Prop1 // won't compile. Can't reference Prop1 here.
};
Console.WriteLine(c.Prop1);
Console.WriteLine(c.Prop2);
Addressing your last question:
Is there a better way that I get around this and still use the object initializer?
So one of your concerns is that because C# doesn't allow referencing other properties in an object initialization statement, that it causes you to violate the DRY principle. But really, all you need to do is use variables:
Working C# example that doesn't violate DRY principle:
string temp = "abc";
var c = new SomeClass
{
Prop1 = temp,
Prop2 = temp
};
Console.WriteLine(c.Prop1); // prints "abc"
Console.WriteLine(c.Prop2); // prints "abc"
Why doesn't c# allow this? I think it should.
Obviously, only the designers of the language can truly answer that one. But I can at least share why I like C#'s design decision better. For instance, in the VB.NET version, if I mistakenly initialize the properties in a different order:
Dim c = New SomeClass With {
.Prop2 = .Prop1,
.Prop1 = "abc"
}
Console.WriteLine(c.Prop1) 'prints "abc"
Console.WriteLine(c.Prop2) 'prints nothing
... the code is still "legal" but I've now inadvertently introduced a bug, and Prop2 is now initialized incorrectly.
Because C# disallows this, it prevents most bugs related to the order of property initialization. I agree that in this very simplified example it's hard to imagine anyone falling for that mistake. But with more properties and more complicated initialization statements, it may not be so obvious, and mistakes can more easily be made. C# helps you avoid these subtle bugs.
I think converting legacy code to c# should be as painless as possible.
I guess you're implying that VB.NET is a legacy language? Some may take offense :)
But more seriously, are you implying that language design decisions should be made to facilitate migration from other languages? C# and VB.NET are two full featured languages in their own right. They are not meant to have matching and symmetrical language designs. If they did, what would be the point of having 2 separate languages?
No. They are 2 different languages with 2 different philosophies. We should consider ourselves lucky that the migration path is as easy as it is currently. There is no reason why it needs to be.
For a little background information, I've got an application that's running in a loop, and over ever tick it calls a method Tick. There's a bunch of classes that extend a base class and all have their own tick methods, and get added to a dependency chain so that say when class A gets called and it's chain has instances of B and C in it, B.Tick gets called, followed by C.Tick, and then finally A.Tick.
So in pseudo code my class kind of looks like this:
public class A : Super
Super b;
Super c;
ArrayList one;
ArrayList two;
tick(){
one.Add(b.LastValue);
two.Add(c.LastValue);
... do something with one and two ...
}
A(){
b = new B(some other array list);
c = new C(ref one);
}
B is working fine, and always gets the correct value. The problem is I guess you can't store a reference to another variable in a class, so when I do new C(ref one); and the contructor for C is setting a class variable to one, later on after one is updated in A it's like C no longer knows that its still supposed to be pointing towards one (which is now updated) and is just empty (like it originally was inside the constructor). Any idea on how to achieve what I'm looking to do, without having to use C# pointers and unsafe code? Thanks, hopefully it makes sense :)
Edit:
Apparently people can't answer questions with confusing pseudo code that is completely unrelated to the actual question, so changed extends to :
Edit 2: C class
...
ArrayList local;
...
C(ref ArrayList one){
local = one;
}
Tick(){
LastValue = local[0] + 5; //not actual formula, just shows trying to use a referenced variable
}
Since one is an ArrayList, you can only pass it as a reference. You are now apparently passing it as a reference-to-a-reference to the constructor. You may not need that ref.
But please show a more complete idea of what you are trying to accomplish.
Edit:
After seeing your C class, there is no need for the ref. c will share the instance of the ArrayList that A calls one.
This seems to boil down to the general referencetype/valuetype issue in .NET. To summarize:
instances of objects do not have a name and cannot (physically) be passed as parameter at all.
you always access an instance through a reference. In your code, one (2x) , two, local are all references to Arraylist instances.
the references themselves behave like valuetypes, ie assignment means copying.
To learn more about referencetypes/valuetypes, search for 'copy semantics' and avoid postings that start with 'valuetypes exist on the stack'.
There's nothing to prevent you from doing this. Whether or not it's a good idea is another question though. In general, I'd recommend trying to avoid changing state between method calls if you can avoid it. Of course, the key expression there is "if you can avoid it". :-)
you can't store a reference to another variable in a class
You can, people do it all the time. Simply assign it to a (private) field.
so when I do new C(ref one); [snip /] later on after one is updated in A it's like C no longer knows that its still supposed to be pointing towards one
Actually, it does know that, but you should assign one to a member field. Assigning to objects is nothing more then setting a reference to the object. Changing the object, changes them everywhere you've assigned it:
class A
{
public string Hello { get; set; }
}
class C
{
private A myA;
public C(A a) { myA = a; }
public A GetMyA() { return myA; }
}
// somewhere else:
A someA = new A();
someA.Hello = "Hello World";
C someC = new C(someA);
someA.Hello = "Other World";
Console.WriteLine(someC.GetMyA().Hello);
// this will print "Other World" and not "Hello World" as you suggest
PS: since you were posting pseudocode, I hope you don't mind me simplifying it a bit. If I misunderstood your question, then please disregard (and perhaps clarify, if possible).
PPS: rereading your (edited) code and still trying to figure out what the problem is, there seems to be nothing that prevents C in your code from keeping a member with a reference to A and calling a.Add will obviously reflect the member variable in c as well. Indeed, no need for ref here.
How can I unset variable? For example, PHP has an unset($var) function.
There is not really an equivalent to "unset".
The closest match I know is the use of the default keyword.
For example:
MyType myvar = default(MyType);
string a = default(string);
The variable will still be "set", but it will have its default value.
You can't. There's no notion of "unsetting" a variable. You can set it to a different value - 0, null, whatever's appropriate. Instance/static variables don't even have a concept of whether the variable is set/unset, and local variables only have "definitely assigned" or "not definitely assigned".
What is it you're trying to achieve?
Generally setting it to null does the job (for variable of types like int you would have to make it a nullable version int?).
If you only want to use the variable for a short period of time in a bigger function you can scope it, like this:
{
int i = 2;
}
The variable will only last until the closing brace.
If these do not cover your circumstance then can you elaborate on where you need to do this.
Maybe you'd like to free the object that the variable is referencing:
MyVar = null;
Value-type variables don't need unset. They are permanently allocated.
For reference-type variables you just set them to null and the garbage collector will destroy the associated object (and free the memory). But note that the variable itself will continue to exist throughout its scope (code block, method, object life, ...)
If you want to use this to free memory then just set all not-needed objects to null and wait for the garbage collector to do its job.
Edit: As noted in comments I ommited to say that the garbage collector won't start the collection immediately. This will happen usually when the framework tries to allocated memory and can't find enough free. It's possible to start "manually" a garbage collection, but it's not advisable and might worsen the behavior of the program. For most purposes the default behavior of the GC should be enough.
To unset environment variable use the same Environment.SetEnvironmentVariable method, but pass null, or string.Empty as a value http://msdn.microsoft.com/en-us/library/96xafkes(v=vs.110).aspx
"If value is empty and the environment variable named by variable exists, the environment variable is deleted."
For an object you can set it to null, a string is best set to String.Empty, or you can declare a variable as nullable such as:
int? i = null;
You could define a scope for that variable. When the scope exits, the variable will no longer be defined:
System.Console.WriteLine("let's give this a try: ");
{
int j = 0;
System.Console.WriteLine(j);
}
//Won't compile with the following line.
//System.Console.WriteLine(j);
personally I just go
variable = Nothing
that seems to free up the resources especially when working with mobile phones!
I think you need to make it null, and to do so:
int? Foo = 5;
Foo = null;