`CallerArgumentExpression` is always null (C# 10) - c#

I'm trying to use the CallerArgumentExpression attribute, in conjunction with the suggestion for validating records found here, but the expression is always null. I am doing this in a .NET6 Core console application. The exact same code works fine in LinqPad 7 (.NET6).
I have a base record that contains common validation methods (pretty much copied from that other answer)...
public record CommonValidation {
internal static bool NonEmptyOrNullString(string s, [CallerArgumentExpression("s")] string expr = default) {
if (string.IsNullOrWhiteSpace(s)) {
throw new ArgumentException($"{expr} cannot be null or empty");
}
return true;
}
internal static bool NonZeroInt(int n, [CallerArgumentExpression("n")] string expr = default) {
if (n < 0) {
throw new ArgumentException($"{expr} cannot be negative");
}
return true;
}
}
I can then create a record as follows...
public record Address(string Street, string City, string State, string Country, string Postcode) : CommonValidation {
private bool _ = NonEmptyOrNullString(Street)
&& NonEmptyOrNullString(City)
&& NonEmptyOrNullString(State)
&& NonEmptyOrNullString(Country)
&& NonEmptyOrNullString(Postcode);
}
If I try to create an Address with an empty State...
Address a = new("5 My Street", "Somewhere", "", "Oz", "12345");
...then the exception is thrown, but the expr variable is null. As I said, the exact same code works fine in LinqPad, even though both are using the same version of .NET/C#.
Anyone able to explain what's going wrong in the console app? Thanks

Visual Studio 2019 doesn't support C# 10. Make sure you're using Visual Studio 2022. LinqPad 7 does which is why it works there.

Related

How to fix this "Invalid expression" term and syntax error in C#

I have an error in the code below please the best solution.
I'm using visual studio 2012
Errors are as follows:
Invalid expression term '.'
Syntax error, ':' expected
Thanks
public event JobCreatedHandler OnJobCreated;
private void DocPrinter(SafePrinter printer, string documentName, string dataType, Stream stream, bool paused, int pagecount, string printerName)
{
var di1 = new DOC_INFO_1
{
pDataType = dataType,
pDocName = documentName,
};
var id = printer.StartDocPrinter(di1);
if (paused)
{
NativeMethods.SetJob(printer.DangerousGetHandle(), id, 0, IntPtr.Zero, (int) JobControl.Pause);
}
// this line throws "Invalid expression term '.'" and "Syntax error"
OnJobCreated?.Invoke(this, new JobCreatedEventArgs {Id = id, PrinterName = printerName});
try
{
PagePrinter(printer, stream, pagecount);
}
finally
{
printer.EndDocPrinter();
}
}
The "?." (null-conditional operator) syntax is available in C# 6 and higher. Visual Studio 2012 supports C# 5 only (at least out-of-the-box, see below).
You might replace the syntax by an if statement:
if (OnJobCreated != null)
OnJobCreated(this, new JobCreatedEventArgs {Id = id, PrinterName = printerName});
Or use a newer Visual Studio version.
Note: I never did it, but it seems to be possible to add C#6 support to VS2012: C# 6.0 Support in Visual Studio 2012.
This is a bit of a guess because you haven't provided enough code but I think you might be mixing up the JobCreated event and the OnJobCreated method. If you are using the usual convention for events then OnJobCreated should be a method, so having a ?. after it makes no sense. In that OnJobCreated method you would raise the JobCreated event by doing JobCreated?.Invoke. Basically, you should have this:
public event EventHandler<JobCreatedEventArgs> JobCreated;
protected virtual void OnJobCreated(JobCreatedEventArgs e)
{
JobCreated?.Invoke(this, e);
}
and then that offending line of code becomes this:
OnJobCreated(new JobCreatedEventArgs {Id = id, PrinterName = printerName});

Phone version of Universal App seems to be caching database even after uninstall

I'm working on a Universal App using SQLite, and I've been using this tutorial along with SQLite for Windows Runtime (Windows Phone 8.1) and sqLite-net to get started.
I'm using this to check if the database exists:
bool exists = true;
try {
var file = await ApplicationData.Current.LocalFolder.GetFileAsync( "database.db" );
} catch {
exists = false;
}
and if not running some insert queries to populate default data:
if( !exists ) {
var conn = new SQLiteConnection( "database.db );
conn.CreateTable<MyClass>();
MyClass.Insert( "Default data value" );
}
where MyClass is
[Table( "MyClass" )]
public class MyClass {
public MyClass() {
this.ID = -1;
this.Name = string.Empty;
}
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
[NotNull]
public string Name { get; set; }
internal static void Insert( string Name ) {
var myclass = new MyClass();
myclass.Name = Name;
var conn = new SQLiteConnection( "database.db" );
try {
if( myclass.ID == -1 ) conn.Insert( myclass );
} catch { }
}
public async static Task<List<MyClass>> List() {
var conn = new SQLiteAsyncConnection( "database.db" );
var rs = conn.Table<MyClass>().OrderBy( t => t.ID );
return await rs.ToListAsync();
}
}
The problem is every time I do a fresh deploy (after uninstalling from my test device), and the code correctly determine the database doesn't exist and performs the inserts, I'm left with an increasing number of records. More specifically, I'm doing an insert of four default values, but at my last deploy that table currently has 124 records (meaning I've deployed 31 times) and looking at the data, it's the same four values repeated. Stepping through the code, only four inserts are occurring, as expected.
It seems like the database is being cached somewhere. I've run the Windows Phone Power Tools and verified there are no files after uninstall. Am I missing something here?
I had a similar problem some time ago (although not with SQLite). Try to check the "Disable automatic backup/restore" checkbox in WMAppManifest.xml (Packaging tab).
In general though, new SQLiteConnection( "database.db" ); by itself does not guarantee a new file being created and your code doesn't currently ensure the file does not already exist: you are catching all exceptions while your condition is only covered by FileNotFoundException - the GetFileAsync may fail for other reasons than the file not existing. I would suggest catching the FileNotFoundException exception to begin with, and possibly also creating the file explicitly in code.

Is it possible to use an extension method that also has an out parameter?

Example:
public static string BoolToYesOrNo(this bool text, out string outAsHtmlName)
{
string[] choices = { "Yes", "No", "N/A" };
switch (text)
{
case true: outAsHtmlName = choices[0]; return choices[0];
case false: outAsHtmlName = choices[1]; return choices[1];
default: outAsHtmlName = choices[2]; return choices[2];
}
}
throws an exception that no overload ... takes 1 argument, altough i am using 2 arguments.
myBool.BoolToYesOrNo(out htmlClassName);
this is the exact exception: CS1501: No overload for method 'BoolToYesOrNo' takes 1 arguments.
This works fine for me with your code:
static void Main()
{
bool x = true;
string html;
string s = x.BoolToYesOrNo(out html);
}
Most likely, you are missing using directive to the namespace of the type that declares BoolToYesOrNo, so add:
using The.Correct.Namespace;
to the top of your code file, where:
namespace The.Correct.Namespace {
public static class SomeType {
public static string BoolToYesOrNo(this ...) {...}
}
}
I tried your code this way and it works without any exceptions, the only thing I would point out if you are giving a parameter with out then you don't need the method to do any return of string
bool b = true;
string htmlName;
string boolToYesOrNo = b.BoolToYesOrNo(out htmlName);
This is what I did to test this out:
I created a new C# Console Application (framework 4.5) in Visual Studio 2012 RC
Changed program.cs to look like this
(omitting usings)
namespace ConsoleApplication1
{
public static class testClass
{
public static string BoolToYesOrNo(this bool text, out string outAsHtmlName)
{
string[] choices = { "Yes", "No", "N/A" };
switch (text)
{
case true: outAsHtmlName = choices[0]; return choices[0];
case false: outAsHtmlName = choices[1]; return choices[1];
default: outAsHtmlName = choices[2]; return choices[2];
}
}
}
class Program
{
static void Main(string[] args)
{
bool b = true;
string result = string.Empty;
string retval = b.BoolToYesOrNo(out result);
Console.WriteLine(retval + ", " + result); //output: "Yes, Yes";
}
}
}
I hit F5 to run the program. The code ran perfectly. So, your method is in fact correct, and there is something wrong ... well, somewhere else. Double check the braces, sometimes if you miss one you get odd errors.
I simply paste your code and it works fine. I tried both .net 3.5 and 4.0 and no compile error is shown and the results are correct.
Why this is an overload method?
Found the answer on a MS forum, was a vs 2012 bug, and after installing the july 2012 update, everything worked fine. Thank you.

help with NullReference exception in C#

The following is a web method that is called from ajax, I have verified with firebug that the script is indeed passing two string values to my method:
public string DealerLogin_Click(string name, string pass)
{
string g="adf";
if (name == "w" && pass == "w")
{
HttpContext.Current.Session["public"] = "pub";
g= "window.location = '/secure/Default.aspx'";
}
return g;
}
I'm passing "w" just for testing purposes. If I delete the if block then I don't get an error back from the server. I'm confused.
Without seeing the stack trace, I would guess that HttpContext.Current or HttpContext.Current.Session is null.
Jeff is correct, but I wanted to add that using session within a web service requires that session be turned "on":
[WebMethod(EnableSession=true)]
public string DealerLogin_Click(string name, string pass)
{
string g="";
if (name == "w" && pass == "w")
{
Session["Public"]="pub";
g= "window.location = '/secure/Default.aspx'";
}
return g;
}

Custom workflow activity errors 'Value cannot be null'

I'm creating a custom workflow activity in VS2010 targeting .NET 3.5. The DLL is actually being used in a Microsoft System Center Service Manager custom workflow, but I don't think that is my issue.
I have a public string property, that the user types in the string of what the activity should use. However, when the WF runs, it errors out 'value cannot be null'. I want to target if it is my code or something else.
When we drag my custom activity onto the designer, I'm able to type in the text of the string on the designer for that property.
public static DependencyProperty ChangeRequestStageProperty = DependencyProperty.Register("ChangeRequestStage", typeof(String), typeof(UpdateChangeRequestStage));
[DescriptionAttribute("The value to set the ChangeRequestStage Property in the ChangeRequest Extension class.")]
[CategoryAttribute("Change Request Extension")]
[BrowsableAttribute(true)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
public String Stage
{
get { return ((String)(base.GetValue(UpdateChangeRequestStage.ChangeRequestStageProperty))); }
set { base.SetValue(UpdateChangeRequestStage.ChangeRequestStageProperty, value); }
}
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
EnterpriseManagementGroup emg = CreateEMG();
//System.WorkItem.ChangeRequest Extension - ClassExtension_928bec0a_cac4_4a0a_bd89_7146c9052fbe
ManagementPackClass mpcChangeRequest = emg.EntityTypes.GetClass(new Guid("8c6c6057-56ad-3862-47ec-dc0dde80a071"));
//System.WorkItemContainsActivity Relationship Class
ManagementPackRelationship workItemContainsActivityRelationship = emg.EntityTypes.GetRelationshipClass(new Guid("2DA498BE-0485-B2B2-D520-6EBD1698E61B"));
EnterpriseManagementObject changeRequest = null;
//Loop thru each emo (Change Request in this case), and assign it. There will never be more than 1 emo returned
foreach (EnterpriseManagementObject obj in emg.EntityObjects.GetRelatedObjects<EnterpriseManagementObject>(executionContext.ContextGuid, workItemContainsActivityRelationship, TraversalDepth.OneLevel, ObjectQueryOptions.Default))
{ changeRequest = obj; }
EnterpriseManagementObjectProjection emop = new EnterpriseManagementObjectProjection(changeRequest);
if (emop != null)
{ emop.Object[mpcChangeRequest, "ChangeRequestStage"].Value = Stage; }
emop.Commit();
return base.Execute(executionContext);
}
Since it is getting a 'value cannot be null' error, I'm guessing it's on this line:
emop.Object[mpcChangeRequest, "ChangeRequestStage"].Value = Stage;
I'm going to test and see if hardcoding a value works or not. Any ideas?
enter code here
try this
if (emop != null && emop.Object[mpcChangeRequest, "ChangeRequestStage"] != null)
emop.Object[mpcChangeRequest, "ChangeRequestStage"].Value = Stage
I didn't want to leave this question wide open, so I'm updating it as to how I resolved this (a long time ago).
Rather than working with an EnterpriseManagementObjectProjection (emop), I worked with a standard EnterpriseManagementObject (emo). From there, I was able to follow a similar format from above:
ManagementPackClass mpcChangeRequest = emg.EntityTypes.GetClass(new Guid("8c246fc5-4e5e-0605-dc23-91f7a362615b"));
changeRequest[mpcChangeRequest, "ChangeRequestStage"].Value = this.Stage;
changeRequest.Commit();

Categories

Resources