Name a parameter inside an anonymous method - c#

I'm creating an anonymous method to generate a radom string.
Before declaring the method, I didn't declare any parameter with the name id.
But I couldn't still define string id = string.Empty; inside the method.
// No parameter within name `id` here...
Func<Task<string>> getIdAsync = null;
getIdAsync = async () =>
{
// string id = string.Empty; // error here. try to use `_id` instead of `id`
string _id = string.Empty;
// logic...
return _id;
};
// _id = ""; // we cann't re-use `_id` here, but `_id` can use `id` below
// `id` is declared after the method
string id = await getIdAsync();
Maybe I misunderstood but I think it should throw me the error when (only in this case):
// declare `id` before
string id = string.Empty;
Func<Task<string>> getIdAsync = null;
getIdAsync = async () =>
{
/*
* A local or parameter named 'id' cannot be declared in this scope
* because that name is used in an enclosing local scope to define a local or parameter
*/
string id = string.Empty;
// logic...
};
id = await getIdAsync();
Can anyone correct me?

This is correct.
You are trying to redeclare the variable id.
The solution will depend on what you are trying to do. If you want to set id then simply remove the type definition;
getIdAsync = async () =>
{
id = string.Empty;
// logic...
};
However, this isn't good practice as id could get overwitten by code outside your async method - unless you actually want this. If this is just a variable local to the scope of the anonymous method then rename it:
getIdAsync = async () =>
{
string localId = string.Empty;
// logic...
};
It's the same as if you were declaring an object of the same name inside an if statement or loop.

The compiler doesn't care what order you declare your local variables with respect to your delegate method because it doesn't know when you're going to use your delegate. So regardless of whether or not you have this statement before or after your delegate declaration, you'll still have a conflict:
string id = await getIdAsync();

It's similar to this question, although that question is dealing with a nested scope rather than an anonymous function, but the reasoning is the same.
The scope of id is the entire function, not just the code after declaration. Since there's no way do disambiguate between the "outer" id variable and the id variable local to the anonymous function, the compiler throws an error to make you specify which variable you are referring to.

Related

How to create a LambdaExpression from a string?

I'd like to write a method that takes a string parameter -- say, sLastName -- and returns a very simple Func<string> that has captured that variable and simply returns it. This doesn't work...
Func<string> MyMethod (string myStringVar)
{
return () => myStringVar;
}
...in that if sLastName is "Smith", and I call MyMethod(sLastName).Invoke(), I'll get back "Smith"; but if I then set sLastName to "Jones" and call MyMethod again, I'll still get back "Smith".
So, to make using MyMethod as simple as possible, I'd like to be able to pass sLastName in as a string, and then (assuming sLastName has been declared, is in scope, etc.), by somehow leveraging the Expression class, return a Func<string> with sLastName embedded as a captured variable... like so...
MyMethod("sLastName").Invoke()
...and it would return the current value of sLastName. But I can't see any way of using strings to build Expressions, and haven't yet found such in StackOverflow. Any way to do this?
Thanks in advance! (By the way, I know I can just create the lambda on the fly and pass it in as a parameter; just looking for something even simpler, where I can use only the name of the variable.)
What you really want is for myStringVar to be declared as a ref variable in MyMethod so that it's passed by reference instead of by value (which will copy the value and is why you don't see the updated value). That way the lamda has a reference to myStringVar and will thus return the latest value whenever called. However, ref variables aren't allowed to be referenced in lambda functions.
In your code, you're passing by value:
Func<string> MyMethod (string myStringVar)
{
return () => myStringVar; // When MyMethod is called, the value of myStringVar inside this function and thus the lambda is a copy of what was passed in
}
This would be similar, but without knowing what you're trying to accomplish I'm not sure if it will work for your scenario:
public static void Main()
{
var myStringVar = "Smith";
Func<string> returnMyString = () => MyMethod(ref myStringVar);
Console.WriteLine(returnMyString());
myStringVar = "Jones";
Console.WriteLine(returnMyString());
}
public static string MyMethod(ref string myStringVar)
{
return myStringVar; // myStringVar holds a reference to the one from the Main program and so returns the latest value
}
The output is:
Smith
Jones
Here's a .net fiddle with the example

Roslyn VSIX Convert local variable to global const

I'm making a simple Roslyn Extensions to look for potential consts and make them global. I've written code to convert to a local const first which is working fine:
I have a codeFixProvider who registers a my fix like so:
context.RegisterCodeFix(CodeAction.Create(title: title,
createChangedDocument: c => this.MakeConstAsync(context.Document, declaration, c),
equivalenceKey: title), diagnostic);
My Make Const function looks like so:
private async Task<Document> MakeConstAsync(Document document, LocalDeclarationStatementSyntax localDeclaration, CancellationToken cancellationToken)
{
// Remove the leading trivia from the local declaration.
var firstToken = localDeclaration.GetFirstToken();
var leadingTrivia = firstToken.LeadingTrivia;
var trimmedLocal = localDeclaration.ReplaceToken(
firstToken, firstToken.WithLeadingTrivia(SyntaxTriviaList.Empty));
localDeclaration.GetNearestParent<ClassDeclarationSyntax>();
// Create a const token with the leading trivia.
var constToken = SyntaxFactory.Token(leadingTrivia, SyntaxKind.ConstKeyword, SyntaxFactory.TriviaList(SyntaxFactory.ElasticMarker));
// Insert the const token into the modifiers list, creating a new modifiers list.
var newModifiers = trimmedLocal.Modifiers.Insert(0, constToken);
// If the type of the declaration is 'var', create a new type name
// for the inferred type.
var variableDeclaration = localDeclaration.Declaration;
var variableTypeName = variableDeclaration.Type;
if (variableTypeName.IsVar)
{
var semanticModel = await document.GetSemanticModelAsync(cancellationToken);
// Special case: Ensure that 'var' isn't actually an alias to another type
// (e.g. using var = System.String).
var aliasInfo = semanticModel.GetAliasInfo(variableTypeName);
if (aliasInfo == null)
{
// Retrieve the type inferred for var.
var type = semanticModel.GetTypeInfo(variableTypeName).ConvertedType;
// Special case: Ensure that 'var' isn't actually a type named 'var'.
if (type.Name != "var")
{
// Create a new TypeSyntax for the inferred type. Be careful
// to keep any leading and trailing trivia from the var keyword.
var typeName = SyntaxFactory.ParseTypeName(type.ToDisplayString())
.WithLeadingTrivia(variableTypeName.GetLeadingTrivia())
.WithTrailingTrivia(variableTypeName.GetTrailingTrivia());
// Add an annotation to simplify the type name.
var simplifiedTypeName = typeName.WithAdditionalAnnotations(Simplifier.Annotation);
// Replace the type in the variable declaration.
variableDeclaration = variableDeclaration.WithType(simplifiedTypeName);
}
}
}
var root = await document.GetSyntaxRootAsync(cancellationToken);
// Produce the new local declaration.
var newLocal = trimmedLocal.WithModifiers(newModifiers)
.WithDeclaration(variableDeclaration);
// Add an annotation to format the new local declaration.
var formattedLocal = newLocal.WithAdditionalAnnotations(Formatter.Annotation);
// Replace the old local declaration with the new local declaration.
var newRoot = root.ReplaceNode(localDeclaration, formattedLocal);
// Return document with transformed tree.
return document.WithSyntaxRoot(newRoot);
}
All of this work fine like so, but when I introduce a function to create a FieldDeclaration, the next time I enter the hive, to check the syntax analysis, I hit Ctrl + . and before anything pop up I get an ambigous One Or More Error occured modal.
public FieldDeclarationSyntax ConvertToFieldDeclarationSyntax(SyntaxTokenList modifiers, VariableDeclarationSyntax declaration, SyntaxKind syntaxKind = SyntaxKind.PublicKeyword)
{
return null;
//return SyntaxFactory.FieldDeclaration(new SyntaxList<AttributeListSyntax>(), modifiers, declaration);
}
I'm not sure why but that function above throws causes an error, I never even reference, for some reason I guess loading that assembly conflicts. Does anyone know how to make FieldDeclarationSyntax in Roslyn?
EDIT
So I turned on all exceptions and now I'm seeing that I get an error
Unable to cast object of type 'System.Reflection.RuntimeMethodInfo' to type 'System.Reflection.ConstructorInfo'.
When Inspecting this now I see additonal error with the stack trace here:
This occurs when hitting ctrl + . on my highlighted syntax error rule a modal pops up from the hive:

Define "var" type out of a method scope

I have a method call like this:
public bool IsAlright(...)
{
var myColumns = // some linq query.ToArray();
var theirColumns = (from row in System.IO.File.ReadAllLines(#"ConfigColumns.txt")
where !string.IsNullOrWhiteSpace(row)
select new { TheColumn = row.ToUpper() }).ToArray();
bool isAlright = // join those two above and see if they have anything in commmon.FirstOrDefault
return isAlright;
}
But I think reading the text file every time is a performance hit and I can do it just once.
So I am thinking of pulling it out but how? it is a "var" and I don't know how to pull out a "var" and define it out of the method scope like a cached object or something?
The var keyword is not a type, it just means the compiler will infer the type based on the type of the right-hand side expression.
The type of your var is an array of an anonymous type. You can't declare a field or method of an anonymous type (unless you use object or dynamic), so you need to declare a type that matches the interface of your anonymous object.
In your case, since you're only storing a string, I would recommend, just returning an array of string instead of using an object:
string[] theirColumns = (from row in System.IO.File.ReadAllLines(#"ConfigColumns.txt")
where !string.IsNullOrWhiteSpace(row)
select row.ToUpper()).ToArray();
You can now pull theirColumns out to a field in your class.
You cannot use var outside of method scope. In your case you can either use string[] instead of custom anonymous object, or create a custom class. Then promote the variable to class field and use it in any other method that you need.
First, Declare a class outside the method.
public class YourClassName
{
public string TheColumn {set;get;}
}
I assume each row is just a string, change the type if it's not
change your theirColumns to
YourClassName[] theirColumns = (from row in System.IO.File.ReadAllLines(#"ConfigColumns.txt")
where !string.IsNullOrWhiteSpace(row)
select new YourClassName { TheColumn = row.ToUpper() }).ToArray();
extract it outside the method.

Linq syntax error in ASP MVC controller method

I have a Linq query I need to use in my Index method in the page's controller, however I am getting the following error on the "select new" portion of the code:
Error
Cannot implicitly convert type 'System.Linq.IQueryable<AnonymousType#1>' to 'string'
Action method
public ActionResult Index(string query)
{
var agentProductTraining = "";
if (String.IsNullOrEmpty(query))
{
BlankIndex();
}
else
{
agentProductTraining = from course in db.Course
where
course.CourseDescription.Contains(query)
select new
{
course.CourseCode,
course.CourseDescription,
course.Partner,
course.Status,
course.LastChangeDate,
course.LastChangeOperator
};
}
return View(agentProductTraining.ToList());
}
As the error clearly states, you cannot assign the result of a LINQ query (IQueryable<T>) to a variable of type string.
You should declare the variable in that line:
var agentProductTraining = select ...
You've initialized the variable as a string, so the compiler makes the variable a string type (since you've user the var keyword), but then tried to assign a collection of anonymous types to it.
You can declare it as an object instead or var:
object agentProductTraining; // can safely be overwritten
Also I assume you mean:
return BlankIndex();
in the if block. Otherwise it will fall through to
return View(agentProductTraining.ToList());
where agentProductTraining is going to be null
Of course if you use return BlankIndex in the if block you can simplify the whole thing:
if (String.IsNullOrEmpty(query))
{
return BlankIndex();
}
// don't need an `else` here since the if will return to the caller
var agentProductTraining = from course in db.Course
where
course.CourseDescription.Contains(query)
select new
{
course.CourseCode,
course.CourseDescription,
course.Partner,
course.Status,
course.LastChangeDate,
course.LastChangeOperator
};
return View(agentProductTraining.ToList());

Specifying properties when initialising

void Foo()
{
string ID = "test";
var testctrl = new Control() {ID = (ID**!=null?ID**:ID)};
}
Is it possible to get the value of ID** in the code above? The problem is they both have the same property names.
Please ignore the fact the specific ID assignment is pointless, im just using it as an example.
Putting aside that the code can't possibly compile...
The first ID (ID=) in this syntax refers to the assignment, specifically the member being assigned. On the right-hand-side, it comes down to standard resolution. Which never means the ID of the new object. It will first look at the local ID variable, then after that members (fields etc) on the current instance. To prefer members on the current instance, use this.ID.
You might also want to consider the null-coalescing operator, so if you mean "the local-variable, or the instance-member if it is null, that would be ID ?? this.ID - but an even better idea would be to make unambiguous variable names ;-p
First remark about this line, it looks strange (assigning string to bool):
bool ID = "test";
Second remark, this works fine:
string ID = "test";
var testctrl = new Control(){ ID = (ID==null?ID:ID) };
Third remark: it is a convention in C# to name your local variables start with lowercase letter.
If you want to check if the new controls id is null then you should do this.
void Foo()
{
string ID = "test";
var testctrl = new Control();
if(testctrl.ID==null)
testctrl.ID = ID;
}
The question is not that clear to me, but do you want this:
void Foo()
{
bool ID = "test";
var testctrl = new Control(){ID = (this.ID==null?ID:this.ID)};
}
note, untested.
Seeing your example, I suspect that you don't have the requirement that the ID should be unique?
In general, to avoid nasty problems like this, avoid try using duplicate property names, but maybe your bound to an existing interface.
How about adding an constructor overload which takes the 'outer' ID as a parameter?
void Foo()
{
string ID = "test";
var testctrl = new Control(ID);
}
I think in general, if the property does more than just assignment (argument checking in this case), you should do it in the 'set' of the property itself and not during 'object initialization'.

Categories