How to initialize var?
C# is a strictly/strongly typed language. var was introduced for compile-time type-binding for anonymous types yet you can use var for primitive and custom types that are already known at design time. At runtime there's nothing like var, it is replaced by an actual type that is either a reference type or value type.
When you say,
var x = null;
the compiler cannot resolve this because there's no type bound to null. You can make it like this.
string y = null;
var x = y;
This will work because now x can know its type at compile time that is string in this case.
Initialize var to null
Simply use FirstOrDefault()
instead. The whole point of FirstOrDefault
is to return the first element of the sequence if it exists, or the default value of the element type (i.e. null for all reference types) otherwise.
Note that in other cases where you wish to check for the existence of any elements, using Any()
can sometimes be more efficient than Count() > 0
- it depends on the exact context, but IMO it's a simpler way of expressing what you're looking for anyway.
Why var in JAVA 10 can not be initialized to null?
There are (at least) three possible type inference strategies the compiler could apply to var o = null
:
- pick
Void
- pick
Object
- look for a later initialization and pick that type
All of them are technically feasible, so the question emerges, which one makes the most sense for developers.
Clearly, Void
is pretty useless and I would argue that Object
is not much more useful, either. While correct, picking either of these types is unlikely to help the developer write better and more readable code.
The last option, looking for an initialization, was not adopted on purpose to avoid so-called action-at-a-distance errors:
var parent = null;
// imagine some recursion or loop structure, so this makes more sense
processNode(parent); // expects a parameter of type `Node`
parent = determineParent(); // returns a parameter of type `Node`
If the compiler inferred Node
for parent
because determineParent()
returns it, this would compile. But the code is fragile because changes to the last line, might lead to a different type chosen in the first line and hence to compile errors on the second line. That's not good!
We're used to the fact that changing a type's declaration can lead to errors down the road but here the change (line 3), its effect (line 1), and consequent error (line 2) can be pretty far apart, this making it much more complicated for developers to understand or, better, predict what happens.
By keeping the type inference rules simple, developers have it easier to form a simple but correct mental model of what's going on.
Addendum
There are doubts whether option 3, inferring the type from a later initialization, is indeed technically feasible. My opinion (that it is) is based on my understanding of JEP 286, specifically:
On the other hand, we could have expanded this feature to include the local equivalent of "blank" finals (i.e., not requiring an initializer, instead relying on definite assignment analysis.) We chose the restriction to "variables with initializers only" because it covers a significant fraction of the candidates while maintaining the simplicity of the feature and reducing "action at a distance" errors.
Similarly, we also could have taken all assignments into account when inferring the type, rather than just the initializer; while this would have further increased the percentage of locals that could exploit this feature, it would also increase the risk of "action at a distance" errors.
Initialize value of 'var' in C# to null
var
variables still have a type - and the compiler error message says this type must be established during the declaration.
The specific request (assigning an initial null value) can be done, but I don't recommend it. It doesn't provide an advantage here (as the type must still be specified) and it could be viewed as making the code less readable:
var x = (String)null;
Which is still "type inferred" and equivalent to:
String x = null;
The compiler will not accept var x = null
because it doesn't associate the null with any type - not even Object. Using the above approach, var x = (Object)null
would "work" although it is of questionable usefulness.
Generally, when I can't use var
's type inference correctly then
- I am at a place where it's best to declare the variable explicitly; or
- I should rewrite the code such that a valid value (with an established type) is assigned during the declaration.
The second approach can be done by moving code into methods or functions.
Declare a var without initializing it... just yet
The correct answer here is to drop the use of var
and to correctly specify the type of existingUsers
outside the try...catch
block:
List<User> existingUsers = null; // or whatever is the right type!
try
{
existingUsers = Repo.GetAll(); // This may crash, and needs to be in a try
}
catch (Exception)
{
throw new Exception("some error, don't bother");
}
if (existingUsers.Count > 0)
{
//some code
}
Initializing var type in LINQ
var
is not a type - it means "I don't care to (or can't) specify what the type is - let the compiler do it for me".
In your case, you're assigning it the result of one of two queries, one of which returns an anonymous type, so you can't specify the type since you don't know the name of the anonymous type (hence the term "anonymous").
In order to use var
, the compiler needs some expression at initialization to know what the actual type is.
I'd suggest something like:
var lstCurrent = Type==1
? _context.Customers().Where(t =>t.type=="current").Select(c => new { c.LastName, c.City})
: _context.Customers().Where(...).Select(...)
But note that your "selects" must return the same type (or anonymous types with the exact same fields) or you won't be able to use var
.
In the end I would try to bake the condition into your Where
clause for less repetetive code:
bool isTypeOne = Type==1;
var lstCurrent = _context.Customers()
.Where(t => isTypeOne ? t.type=="current" : ...)
.Select(c => new { c.LastName, c.City})
How to initialize var Record parameter
Using just FillChar
is wrong here. If any of the WideString
members are not empty, then you will leak them this way. Instead I suggest the following:
Finalize(IPInfo);
FillChar(IPInfo, SizeOf(TIPInfo), 0);
Or another way is to define a default record as a typed constant:
const
DefaultIPInfo: TIPInfo = ();
Then you can use simple assignment:
IPInfo := DefaultIPInfo;
In modern versions of Delphi you can instead use this much more readable code:
IPInfo := Default(TIPInfo);
For more on this particular subject, refer to these topics:
- Delphi "default" keyword with Record types in older Delphi versions.
- How to properly free records that contain various types in Delphi at once?
Note that the leak in your code is hard to find because WideString
variables are implemented as COM BSTR
objects, and allocated on the COM heap. Therefore, if you use memory leak detection for the Delphi memory manager the leak will not be detected because it is leaked from a different heap.
In your case, because your record is a managed type, and contains only managed types, then you could use an out
parameter to good effect. For managed types, out
parameters mean that the compiler will generate code, at the call site, to default initialize the record before passing it in.
Consider the following program:
{$APPTYPE CONSOLE}
type
TRec = record
Value: WideString;
end;
procedure Foo1(var rec: TRec);
begin
end;
procedure Foo2(out rec: TRec);
begin
end;
procedure Main;
var
rec: TRec;
begin
rec.Value := 'Foo';
Foo1(rec);
Writeln(rec.Value);
Foo2(rec);
Writeln(rec.Value);
end;
begin
Main;
end.
The output is:
Foo
If your record contains a mix of managed and unmanaged types, then the situation is not so good.
{$APPTYPE CONSOLE}
type
TRec = record
Value1: WideString;
Value2: Integer;
end;
procedure Foo1(var rec: TRec);
begin
end;
procedure Foo2(out rec: TRec);
begin
end;
procedure Main;
var
rec: TRec;
begin
rec.Value1 := 'Foo';
rec.Value2 := 42;
Foo1(rec);
Writeln(rec.Value1);
Writeln(rec.Value2);
Foo2(rec);
Writeln(rec.Value1);
Writeln(rec.Value2);
end;
begin
Main;
end.
The output is:
Foo
42
42
Only the managed members are default initialized for out
parameters. So your best bet is to default initializing the variable yourself, even if it is passed as an out
parameter.
More on out
parameters can be found here: What's the difference between "var" and "out" parameters?
Related Topics
Handling Executescalar() When No Results Are Returned
Initialization Order of Static Fields in Static Class
How to Convert Bitarray to Single Int
Why Can't I Access C# Protected Members Except Like This
How to Capture the '#' Character on Different Locale Keyboards in Wpf/C#
How to Clear the Text of All Textboxes in the Form
Displaynamefor() from List<Object> in Model
The Entity Type Applicationuser Is Not Part of the Model for the Current Context
How to Get the Names of Method Parameters
Textrenderer.Measuretext and Graphics.Measurestring Mismatch in Size
Incremental JSON Parsing in C#
Getting Individual Windows Application Current Volume Output Level as Visualized in Audio Mixer
Should You Implement Idisposable.Dispose() So That It Never Throws
C#: Should Object Variables Be Assigned to Null
Setting Culture (En-In) Globally in Wpf Application
Is There Any Way in C# to Override a Class Method with an Extension Method