Initialize dynamically the var filter - c#

What I'm trying to achieve is to initialize the "filter" variable dynamically based on what my method gets.
Initializing it to null throws an error.
Leaving it empty throws error.
Setting it to a generic type throws an error
Setting it to a new BsonDocument also throws an error
This is my code:
var filter=null;
if (id != 0)
if (subID != 0)
//Get Specific Categories
filter = builder.Eq("Categories.Sub.id", id) & builder.Eq("Categories.Sub.Custom.id", subID);
else
//Get SubCategories
filter = builder.Eq("Categories.Sub.id", id);
else
//Get Generic Categories
filter = new BsonDocument();
I've been searching but nobody seems to have my problem or I'm not able to find it.

Var is not a dynamic variable, it is a keyword for type inference. These are very different concepts. The key issue is that in your code snippet the compiler can not figure out what kind of variable you want your var to be.
var myNumber = 3; // myNumber is inferred by the compiler to be of type int.
int myNumber = 3; // this line is considered by the computer to be identical to the one above.
The inferred type of a var variable does not change.
var myVariable = 3;
myVariable = "Hello"; // throws an error because myVariable is of type int
The type of dynamic variables can change.
dynamic myVariable = 3;
myVariable = "Hello"; // does not throw an error.
The compiler must be able to determine the type of an object when a var variable is created;
var myVariable = null; // null can be anything, the compiler can not figure out what kind of variable you want.
var myVariable = (BsonDocument)null; // by setting the variable to a null instance of a specific type the compiler can figure out what to set var to.

With var it's an implicit type and you can initialize a implicit type variable to null since it can be both value type and reference type; and value type can't be assigned to null (unless otherwise it's made nullable explicitly).
Thus instead of saying var filter=null; you should explicitly specify the type
BsonDocument filter = null;

Related

How can I set a List<foo> field of an object with the value of List<dynamic>

I have been trying to set some field values of specific objects in C#.
For other reasons I need to construct a List of values from a string then I want to assign this to a field in an object.
The way I indicate the value type of the list is something like this in string
name:type{listItemName:listItemType{listItemValue}}
This list can be of any type, so it is undetermined until we reach conversion.
I am using
List<dynamic> ldy = new List<dynamic>();
foreach (string listElement in listElements)
{
if (listElement == "") continue;
Type leDataType = GetDataType(listElement);
string leData = GetDataRaw(listElement);
var leDynamic = ConstructDataObject(leDataType, leData, listElement);
ldy.Add(leDynamic);
}
Which ends up with the correct data and with the correct data type when I enquire, however when I am trying to use the resulting ldy list and assign it to a field, of course it acts as a List<object>
thus not allowing me to assign.
Finally so, I am using field.SetValue(targetObject, ldy); to assign the value to the field.
The error message I am getting is
ArgumentException: Object of type 'System.Collections.Generic.List`1[System.Object]' cannot be converted to type 'System.Collections.Generic.List`1[System.Int32]'.
Which to be clear, I do understand and I do understand why, however I dont really see how could I solve this issue, not by solving this nor by changing the fundaments of my code design.
Please help!
As #juharr suggested I have searched for solutions to do this with reflection.
Here is my solution:
private static IList GetTypedList(Type t)
{
var listType = typeof(List<>);
var constructedListType = listType.MakeGenericType(t);
var instance = Activator.CreateInstance(constructedListType);
return (IList)instance;
}

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:

Can not implicity convert type Systems.Collection.Generic.List<feedEventViewModel> to Proj.Areas.Management.Models.FeedEventViewModel

I'm trying to convert a view model to list and then return it to the view but am getting the cannot implicity convert type error.
Code:
public ActionResult Index(FeedEventCommand command)
{
var feedEventViewModel = new FeedEventViewModel
{
AnimalId = command.AnimalId,
AnimalName = command.AnimalName,
FeederTypeId = command.FeederTypeId,
FeederType = command.FeederType
};
feedEventViewModel = new List<feedEventViewModel>(); <--Error line
return View(feedEventViewModel);
}
What am I doing wrong in this case?
feedEventViewModel is already declared as a single object, you can't declare it again as a List<FeedEventViewModel>(). Other language such as Rust allows you to "shadow" the variable declaration but C# not (and var is just a shorter way to declare a variable).
You can solve this issue quite easily:
return View( new List<FeedEventViewModel>() {
new FeedEventViewModel{
AnimalId = command.AnimalId,
AnimalName = command.AnimalName,
FeederTypeId = command.FeederTypeId,
FeederType = command.FeederType
}
}
);
You may be misunderstanding what the var keyword is doing here. When you declare a variable with var you are not saying that the variable can be anything, you are saying to the compiler that it can work out what the type is without you needing to specify it precisely.
So in your example (or a slight modification) when the compiler encounters the code:
var feedEventViewModel = new FeedEventViewModel();
it will see that the right hand side of the assignment is of type FeedEventViewModel and so the variable feedEventViewModel will be of that type. In effect it will be like you typed:
FeedEventViewModel feedEventViewModel = new FeedEventViewModel();
Any later use of that variable must be in line with this declaration so when you do feedEventViewModel = new List<feedEventViewModel>(); the compiler rightly says that List<feedEventViewModel> is not of the type expected by feedEventViewModel. There is such a thing as implicit conversions whereby the compiler knows how to convert between two different types and is allowed to do it without it being specifically requested but no such implicit conversions were found, hence the error.
It is unclear from the information given what exactly you are doing (is the item you created meant to be on the list? Does your view expect a list or a single item?). If you need a list with the item in then I'd just go with:
var list = new List<feedEventViewModel>(){feedEventViewModel };
return View(list);

SqlParameter Cast in C#

I have a SqlParameter contained in a var coming back from a stored procedure and the value is either Null, an int or -1. How do cast the var to check if it is -1 in C#?
var p_eventID = new SqlParameter()
{
ParameterName = "#EventID",
Value = (eventID.HasValue
? (object)eventID.Value
: (object)System.Data.SqlTypes.SqlInt32.Null),
Direction = ParameterDirection.InputOutput
};
I have tried:
if ((int?)eventID.Value == -1)
But it gives me an invalid cast error.
SQL requests report NULLs to C# through DBNull objects, forcing the cast to fail.
You can do the other kind of cast to int? without triggering an error:
var eventIdInt = eventId as int?;
if (eventIdInt == -1) {
...
}
Rather than throwing an exception, the x as type style of cast would produce a null value when the cast fails.
Your approach when an error occurs, it will throw an Invalid Cast Exception. However, if you utilize the as int if it fails it will return a null. Which will be a bit more graceful, and forgiving.
So you could do the following:
if(eventId != null)
{
// Do Stuff.
}
So that returned value from your scalar, should either contain an actual int or a null.
So in order to solve why you receive the error with the (int) we would need to see how you implement the scalar and know the type of object it is actually returning before the cast.

How to Assign a Query Result to an Integer Array

public List<Workflow> GetMyWorkflows(int[] MyRoles)
{
int[] myWorkflowIDs = new int[] { };
RapidWorkflowDataContext context = new RapidWorkflowDataContext();
var query = from w in context.WorkflowRoles
where MyRoles.Contains((int)w.RoleID)
select w.WorkflowID;
var distinctWorkflows = query.Distinct();
myWorkflowIDs = distinctWorkflows.toArray();
return myWorkflowIDs;
}
In this method I want to retrieve an array of workflows that a user can
access.
I get the following error : Cannot implicitly convert type 'int?[]' to 'int[]'
I want to retrieve an array of workflows
But your method must return a List<Workflow> or a List<int>.
So you should skip the array idea. The other issue is between int and int?. You can solve that in the select clause with select w.WorkflowID.Value or select w.WorkflowID ?? 0. Or simply select w for a List<Workflow>.
Also it is a good idea to dispose a context when it becomes unreachable.
public List<int> GetMyWorkflows(int[] MyRoles)
{
using (RapidWorkflowDataContext context = new RapidWorkflowDataContext())
{
var query = from w in context.WorkflowRoles
where MyRoles.Contains((int)w.RoleID)
select w.WorkflowID ?? 0;
// select w; to return a List<WorkFlow>
var distinctWorkflows = query.Distinct();
return distinctWorkflows.ToList(); // ToList because we are closing the Context
}
}
I'm going to guess that WorkflowID is of type int?. If you are certain that it cannot be null, change your central query to:
var query = from w in context.WorkflowRoles
where MyRoles.Contains((int)w.RoleID)
select w.WorkflowID.Value;
This will ensure that query is now of type IEnumerable<int> instead of IEnumerable<int?>, with the int following on throuhh the Distinct() and ToArray() functions.
This seems like a pretty good error to me
Cannot convert type 'int?[]' to 'int[]'
You must have an array of type int? and be trying to implicitly convert it to int.
Therefore you have two options - stop trying to implicitly convert, and allow the result to be int?[], like this:
int?[] myWorkflowIDs = new int?[] { };
or force the convert to take place, like this:
RapidWorkflowDataContext context = new RapidWorkflowDataContext();
var query = from w in context.WorkflowRoles
where MyRoles.Contains((int)w.RoleID)
select (int)w.WorkflowID;
// or w.WorkflowID ?? 0; as necessary
So int? can also be written Nullable<int> which is basically an int that can take null values. For example:
int? nullableNumber = 5; // Set to a value
nullableNumber = null? // Set to null (which is possible because int? is nullable).
As you can imagine, Nullable<int> is useful for databases because sometimes you might have a column that has null values, and so this type gives a useful means of mapping to this sort of value. The problem, though is that in your code you have to deal with two different types, int vs. int?. You can cast between the two values by using:
// If the nullable-integer is not-null then use it's value, else default to `0`.
int nonNullable = nullableNumber ?? 0;
which will replace nulls with 0 if the value is null. Or you can just store your myWorkflowIDs in a nullable value (Nullable<int>[] or int?[]), which semantically better reflects what the column value in the database actually is.

Categories