How can i use a var in c# over {} - c#

How can i use a var in c# over {} like:
if
{
var test;
while
{
test = "12345";
//test is defined
}
var test2 = test;
//test is undefined
}
I do not understand it.

You can't use var with uninitialized variable because in this case compiler won't know the real type. var is syntactic sugar - compiler should decide which type to use and in IL code you will see real type.
If you really want var you should initialize it with any value of some type (in your case - string):
if
{
var test = String.Empty; // initialize it - now compiler knows type
while
{
test = "12345";
//test is defined
}
var test2 = test;
//test is undefined
}

You can use object type instead of var then assign null as initialization. It will work for string, int as you wish.
Please check below:
if
{
object test = null;
while
{
test = "12345";
//test is defined
}
var test2 = test;
//test is undefined
}
Please check example in DotNetFiddle.

Var is not a type, var is a keyword that tells the computer to decide which type fits for your value.
You can use this instead:
if
{
var test = "placeholder";
while
{
test = "12345";
//test is defined
}
var test2 = test;
//test is undefined
}
Or better yet, just declare a string from the very start, var is meant to be used when you don't know what type you will need at the point of declaration, when you do know the type you better just declare the reference with the proper type.
Edit:
This code works just fine for me (note that in your original code you were missing the condition
if (true)
{
string test;
while (true)
{
test = "12345";
//test is defined
}
var test2 = test;
//test is undefined
}

Related

'Preserve'/refer to variable names when passed as arguments

Using string interpolation, I'm attempting to write a method which iterates over an arbitrary amount of objects to evaluating both the name and value of each.
So, consider the following:
private string ParametersMessage(params object[] parameters)
{
var msg = "Parameters: ";
for (int i = 0; i < parameters.Length; i++)
{
msg += $"{nameof(parameters[i])}:{parameters[i]}\r\n";
}
return msg;
}
You can't tell from the StackOverflow syntax highlighting - but this ain't working, not in a million years, because parameters[i] has no name, so nameof can't do the job.
I may call this method like so:
int myNumber = 123;
string myWord = "hello";
var myMessage = ParametersMessage(myNumber, myWord);
Now since I've passed myNumber and myWord as arguments, they've lost their name. Do I need to pass a pointer or some other way of referring to the variable name? How can I build a string from each of the objects' names and values in the list?
Context
During logging, I'll often concatenate a whole host of parameter names and values to help diagnose issues more specifically by seeing which particular record/object failed XYZ. I'm trying to make my method generic enough to avoid having to write many string builder methods.
What I've Tried
I've tried the above (you can see my attempt), but I've also considered passing in the result of nameof with the value. But at that point, I've quickly reverted back to making it too specific again.
Note
I'm no expert, but I'm experienced enough to know the above syntax is silly. I suppose you could interpret my question as 'offer me an alternative approach to what I'm illustrating with my code sample above'.
You can't.
And the signature of the method gives it away: From the compilers point of view , and for all practical purposes, it's an anonymized array of values, with no names associated with them.
And to more clearly illustrate, let's for the sake of argument assume you were to call it like:
ParametersMessage(1, 2, 3, 4, 5);
What would the parameter names be in that case?
I am not sure if this is going to help, but you could make something like a fluent interface so that you can construct the message like this:
string msg = Parameters("name1", value1).And("name2", value2).ToString();
UPDATE
This is neither elegant nor rubust, but you can still pass "parameter names" implicitly:
public void Test()
{
var foo = "bla";
var bar = "blub";
var msg = Parameters(() => foo).And(() => bar).ToString();
// msg contains now "foo = bla, bar = blub"
}
Implementation
public class Params
{
private readonly IDictionary<string, object> _params = new Dictionary<string, object>();
public Params And(Expression<Func<object>> exp)
{
var body = exp.Body as MemberExpression;
_params[body.Member.Name] = exp.Compile().Invoke();
return this;
}
public override string ToString()
{
return String.Join(", ", _params.Select(pair => String.Format("{0} = {1}", pair.Key, pair.Value)));
}
}
public Params Parameters(Expression<Func<object>>expr)
{
return new Params().And(expr);
}

Update a variable inside ForEach loop

I simply can't understand why this simple code is not working. My expected output is 10 and 15, but it is returning 2 and 3. That means that the update is not working.
List<int> numbers = new List<int>();
numbers.Add(2);
numbers.Add(3);
numbers.ForEach(n => n = n*5);
numbers.ForEach(n => Console.WriteLine(n));
Note: I've already searched a lot, but I could not understand this behavior.
How should I fix it?
Update: the same behavior for strings.
List<string> strings = new List<string>();
strings.Add("a");
strings.Add("b");
strings.ForEach(s => s = s + "--");
strings.ForEach(s => Console.WriteLine(s));
n is a copy of your current value in the list not a reference to your value.If you want to manipulate the values in your list then use a for loop
for(int i = 0; i<numbers.Count; i++)
numbers[i] *= 5;
More detailed explanation:
With a normal foreach loop your code doesn't even compile:
foreach(var n in numbers)
n = n * 5; // Readonly local variable cannot be used as an assignment target
Remember that List<T>.ForEach loop is not the same as foreach but it is just a method that takes a Action<int> delegate as argument and performs the specified action on the each element in your list.So it performs something like this (taken from the source code):
public void ForEach(Action<T> action)
{
// removed unnecessary parts for brevity
for(int i = 0 ; i < _size; i++)
{
action(_items[i]);
}
}
As you can see here the _item[i] is passed to the action and since int is a value types the copy of your value is passed rather than a reference.And that's why your values didn't change.
For strings: Apart from the fact that strings are immutable, assigning a new reference to a reference type doesn't change the object that holds the same reference.For example consider this:
static void Update(string s)
{
s = "bar";
}
string f = "foo";
Update(f);
Console.WriteLine(f); // foo
Assigning a new reference to s doesn't change the f, f stil holds the old reference and s is pointing to a new location in memory.This is not because s is a copy,it's not.If you change a property of s (with strings you can't do that but try with another reference type), it would update the property of f as well.It works in this way because s and f are two different strings that points to the same location in memory.So s is not bound to f.You can think they were declared like this:
string f = "foo";
string s = f;
s = "bar";
The only exception is when you pass f as a ref argument then the assignment will change the f as well:
static void Update(ref string s)
{
s = "bar";
}
string f = "foo";
Update(ref f);
Console.WriteLine(f); // bar
Because they are value types, rather than mutating the list you could create a modified one using Select
var newList= numbers.Select(n => n = n*5);
As imperative programmers, we love mutating things, which is not a brilliant idea!!
The reason why it did not work for strings is that because by default C# passes a copy of the reference rather than the actual reference.
void Fn(string s)
{
s = "not being changed";
}
Main()
{
var hello = "hello";
Fn(hello);
Console.WriteLine (hello); // prints hello again!!
}
However, if you want to change the reference you have to use the ref keyword.
void Fn(ref string s)
{
s = "Unfortunately, changed!";
}
Main()
{
var hello = "hello";
Fn(ref hello);
Console.WriteLine (hello); // Unfortunately, changed!!!
}
I think that changing parameters' values is a terrible idea and you shouldn't be doing that, you should return a new string that contains the new modifications.
The reason is because the parameter to the ForEach are passed by value and not by reference.
However, if you do pass a reference type, it must work as expected as shown below
class Program
{
static void Main(string[] args)
{
List<Frog> numbers = new List<Frog>();
numbers.Add(new Frog { name = "balcha" });
numbers.Add(new Frog { name = "Tibara" });
numbers.ForEach(n => n.name = "Bontu");
numbers.ForEach(n => Console.WriteLine(n.name));
Console.ReadLine();
}
class Frog
{
public string name { get; set; }
}
}
Output:
Bontu
Bontu

Getting the fully qualified name of a type from a TypeInfo object

Is it somehow possible to get the fully qualified name of the type contained in a TypeInfo object?
In the debugger many of these values nicely show up as System.Int32 but when it's printed out, not one of them contains this fully qualified name. I need this to provide as an argument to Type.GetType().
var typeInfo = semanticModel.GetTypeInfo(argument);
var w = typeInfo.ToString(); // Microsoft.CodeAnalysis.TypeInfo
var y = typeInfo.Type.ToString(); // int
var z = typeInfo.Type.ToDisplayString(); // int
var a = typeInfo.Type.OriginalDefinition.ToDisplayString(); // int
var b = typeInfo.Type.OriginalDefinition.ToString(); // int
var c = typeInfo.Type.Name; // Int32
var d = typeInfo.Type.MetadataName; // Int32
var e = typeInfo.Type.ToDisplayParts(); // {int}
var f = typeInfo.Type.ContainingNamespace; // System
Note that this should work for every type so I can't just concatenate the namespace with the name.
Alternatively: is there another (more suited?) way to get the exact type?
For context: I want to check if the type-parameters of a class contain a few specific methods. Therefore my approach was to get the parameters from the TypeArgumentListSyntax and get the TypeInfo from each TypeSyntax object.
The ToDisplayString method lets you pass in a "format" object which has a huge number of options for controlling how you want to format stuff:
var symbolDisplayFormat = new SymbolDisplayFormat(
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces);
string fullyQualifiedName = typeSymbol.ToDisplayString(symbolDisplayFormat);
The reason your getting keywords like "int" is the default format is including the SymbolDisplayMiscellaneousOptions.UseSpecialTypes flag which specifies to use the language keywords for special types vs. the regular name.
I couldn't find something built-in either and I'm quite sure this isn't the most elegant way, but it worked for me to construct a qualified type name like this:
private static string GetQualifiedTypeName(ISymbol symbol)
{
return symbol.ContainingNamespace
+ "." + symbol.Name
+ ", " + symbol.ContainingAssembly;
}
If you don't need an assembly qualified type name don't concatenate ContainingAssembly at the end of the last line.
Using the semantic model you can also do it like i did it here:
var typeInfo = context.SemanticModel.GetTypeInfo(identifierNameSyntax);
var namedType = typeInfo.Type as INamedTypeSymbol;
if (namedType != null && namedType.Name == nameof(ConfiguredTaskAwaitable) && GetFullNamespace(namedType) == typeof(ConfiguredTaskAwaitable).Namespace)
return true;
where "GetFullNamespace" works like this:
public static IEnumerable<string> GetNamespaces(INamedTypeSymbol symbol)
{
var current = symbol.ContainingNamespace;
while (current != null)
{
if (current.IsGlobalNamespace)
break;
yield return current.Name;
current = current.ContainingNamespace;
}
}
public static string GetFullNamespace(INamedTypeSymbol symbol)
{
return string.Join(".", GetNamespaces(symbol).Reverse());
}
public static string GetFullTypeName(INamedTypeSymbol symbol)
{
return string.Join(".", GetNamespaces(symbol).Reverse().Concat(new []{ symbol.Name }));
}
Obviously Jason Malinowski's answer is more convenient for simple cases

Do synonyms exist?

Is there a way to have a variable set to an object and have another variable which is always equals to the former one?
var x = new object();
var y = [synonym of x];
x = null; // then y = null as well
I don't think this exists.
So I've often used arrays to hold "references".
var x = new object[] { new object() };
var y = x;
x[0] = null; // then y[0] = null as well
But it feels kinda lame.
If you really really need to this you can do something like below but I think it is still lame (:
class RefHolder<T>
{
public RefHolder(T value)
{
Value = value;
}
public T Value { get; set; }
}
Usage
var o1 = new RefHolder<object>(new object());
var o2 = o1;
o2.Value = null; // now o1.Value is null too
You can do it but the price you have to pay is to use undocumented keywords/features. They're there from long time ago and probably they won't change or disappear but...
It'll make your code more complicated to read (it may be useful if supported by the language itself) but it's bidirectional and you can move around your original object, changes will always be reflected to your "reference" too. It differs from Mehmet Ataş answer because you can pass the original object to another function and changes will propagate to your synonym too. They have limitations (they can't be used for class fields) but they works for parameters and local variables.
What you need is a TypedReference, it holds a reference to another variable then if you assign a new value to it you'll change the original variable. This in theory could open the door to synonyms if someday they'll think it's a good feature to include.
Let's see an example:
var text = "initial value";
var synonym = __makeref(text);
Now synonym is a reference to text (please note it's a reference to text and not to the value it holds). To get original value from a TypedReference you use __refvalue like this:
Console.WriteLine(__refvalue(synonym, string));
They have the same value:
Debug.Assert(__refvalue(synonym, string) == text);
Now let's change text to a new value:
text = "second value";
Debug.Assert(__refvalue(synonym, string) == text);
And even opposite is true:
__refvalue(synonym, string) = "third value"; // <---
Debug.Assert(__refvalue(synonym, string) == text);
Finally let's modify the original variable within another function (unaware of the reference it'll see a normal variable):
void ChangeIt(ref string value) { value = "another value"; }
ChangeIt(ref text);
Debug.Assert(__refvalue(synonym, string) == text);
All of this works will value types as well. Note that this creates a synonym for a variable, not an alias (you can imagine them as a safe pointer - to pointer in case of reference type). Let's try this:
void foo1()
{
string text = "ABC";
foo2(text);
// text holds the original value "ABC"
// not the value modified in foo2
}
void foo2(string value)
{
value = "123";
var synonym = __makeref(value);
__refvalue(value, string) = "456";
// both value and synonym holds "456";
}
Well, you are basicly describing a C++ reference (or a C pointer).
This can be done in C#, too, but you REALLY do not want to do this unless you absolutely need to.
unsafe static void Main(string[] args)
{
int a = 5;
int *b = &a;
*b = 0;
Console.WriteLine(a);
}
This will output 0 to the console.
You can read more about unsafe code in Unsafe Code and Pointers article on MSDN.
It depends. .NET contains both Reference and Value types. Value types are all the basic types, int, bool etc.. plus string. Reference types are everything else, including anything you create for yourself.
So, for example, value types...
int a = 3;
int b = a;
b = 5;
// a is still 3
While with references
class Mine {
public int A { get; set; }
}
Mine A = new Mine() { A = 3; }
Mine B = A;
B.A = 5;
// A.A is now 5.
you can asign like
var parentObject={};
parentobject['child1']="test1";
parentobject['child2']="test2";
parentobject['child3']="test3";
after
console.log(parentObject);
you get following output
object{child1="test1",child2="test2",child2="test2"}

C# array of variables

Is it possible to do something like this:
string A = "A";
string B = "B";
object[] O = { A, B };
O[0] = "C";
Where A will hold the value "C" in the end?
The code above will replace O[0] with "C", but A remains unchanged.
No - at least not in safe code.
When you create the array, it copies the values into the array. Changing the value in the array later won't change the value of the variable. There's no way of creating a sort of "ref array", where the array elements are shared with the variables. (As shown in Mark's answer, there are sometimes ways of doing this in unsafe code, but I'd really suggest staying away from that.)
Note, however, that if both the array and the variable refer to the same mutable object then mutating that object via either path will make a change which is visible via the other:
StringBuilder x = new StringBuilder();
StringBuilder[] array = new StringBuilder[] { x };
array[0].Append("Foo");
Console.WriteLine(x); // Prints "Foo"
This is no different to any other assignment though - and note that in the code above, the Append call doesn't change the value of either x or the array element; it changes the data within the object that those values refer to.
While the answer is no in the case of string, you can do this with value types:
class Program
{
static unsafe void Main()
{
char A = 'A';
char B = 'B';
var O = new char*[] { &A, &B };
*O[0] = 'C';
System.Console.WriteLine(A + "," + B); // outputs C,B
}
}
Unsafe code is typically frowned upon in C#. So, while this kind of thing is possible, I wouldn't recommend doing it.
What you probably want is to convert your strings into objects with properties.
You can then Cast your array object on the specific key to this object type you created, and then you can set its property again.
This way you can change both what's in your array, as your original variable, therefor, it is similar to seeing it as an array with values by reference.
public class stringObject
{
private string name;
public string Name { get { return name; } set { name = value; } }
}
stringObject A = new stringObject();
A.Name = "A";
stringObject B = new stringObject();
B.Name = "B";
object[] O = { A, B };
//change the array at key 0, and also changing our original variable
stringObject C = O[0] as stringObject;
C.Name = "C";
The above code will not only change what is inside O[0], but it will also update what is inside your object A.
An example with a test to write to the console can be seen here:
https://dotnetfiddle.net/Yt25hy

Categories

Resources