C# 8 introduced nullable reference types, which is a very cool feature. Now if you expect to get nullable values you have to write so-called guards:
object? value = null;
if (value is null)
{
throw new ArgumentNullException();
}
…
These can be a bit repetitive. What I am wondering is if it is possible to avoid writing this type of code for every variable, but instead have a guard-type static void function that throws exception if value is null or just returns if value is not null. Or is this too hard for compiler to infer? Especially if it's external library/package?
There are a few things you can do.
You can use [DoesNotReturnIf(...)] in your guard method, to indicate that it throws if a particular condition is true or false, for example:
public static class Ensure
{
public static void True([DoesNotReturnIf(false)] bool condition)
{
if (!condition)
{
throw new Exception("!!!");
}
}
}
Then:
public void TestMethod(object? o)
{
Ensure.True(o != null);
Console.WriteLine(o.ToString()); // No warning
}
This works because:
[DoesNotReturnIf(bool)]: Placed on a bool parameter. Code after the call is unreachable if the parameter has the specified bool value
Alternatively, you can declare a guard method like this:
public static class Ensure
{
public static void NotNull([NotNull] object? o)
{
if (o is null)
{
throw new Exception("!!!");
}
}
}
And use it like this:
public void TestMethod(object? o)
{
Ensure.NotNull(o);
Console.WriteLine(o.ToString()); // No warning
}
This works because:
[NotNull]: For outputs (ref/out parameters, return values), the output will not be null, even if the type allows it. For inputs (by-value/in parameters) the value passed is known not to be null when we return.
SharpLab with examples
Of course, the real question is why you want to do this. If you don't expect value to be null, then declare it as object?, rather than object -- that's the point of having NRTs.
There is a Guard Clauses library by Steve Ardalis that I think can help you with this situation.
You can do things like:
Guard.Against.Null (throws if input is null)
Guard.Against.NullOrEmpty (throws if string or array input is null or empty)
Guard.Against.NullOrWhiteSpace (throws if string input is null, empty or whitespace)
Guard.Against.OutOfRange (throws if integer/DateTime/enum input is outside a provided range)
Guard.Against.OutOfSQLDateRange (throws if DateTime input is outside the valid range of SQL Server DateTime values)
Guard.Against.Zero (throws if number input is zero)
In this blog post Jason Roberts made a quick explanation of the library too.
There is another Guard Class in the Microsoft.Toolkit.Diagnostics namespace but probably is not viable in all the use cases that will depend if wanna add that dependency to the project or not.
Related
edit; Based on responses, I may have been unclear in my final goal. I've updated the last section.
Situation
I have a number of variables which I need to perform the same operation on. In this case, they are strings, and can at the point we reach this code have the value null, "", "Blank", or they could already have an assigned other value that I want to keep.
if (String.IsNullOrEmpty(MyVar1) || "Blank".Equals(MyVar1))
MyVar1 = null;
if(String.IsNullOrEmpty(MyVar2) || "Blank".Equals(MyVar2))
MyVar2 = null;
...
if(String.IsNullOrEmpty(MyVar10) || "Blank".Equals(MyVar10))
MyVar10 = null;
Being a programmer that wants to keep my code clean and this block drives me mad, I'm looking for a way to create a list of these variables, and perform this same if statement + null assignment on each.
For an example, here's what I'd like to do:
MyVar1 = "Blank";
DreamDataStructure varList = new DreamDataStructure() { MyVar1, MyVar2, ..., MyVar10 };
foreach(ref string MyVar in varList)
{
if(String.IsNullOrEmpty(MyVar) || "Blank".Equals(MyVar))
MyVar = null;
}
Console.WriteLine(MyVar1); //Should now be null
What Doesn't Work
1) Because my variables are strings, I can't do something like this.
var myListOfVariables = new[] { &MyVar1, &MyVar2, ..., &MyVar10 };
If I could, I'd be able to foreach over them as expected. Because string is a managed type though, it cannot be passed by reference like this.
2) Similarly, if I just made a List<string> of the variables, they would be passed by value and wouldn't help my case.
3) These variables can't be wrapped in an outer object type, as they need to be used as strings in a large number of places in a legacy application. Assume that it would be too large an effort to change how they're used in every location.
Question
Is there a way to iterate over string (or other managed type) variables in a pass-by-reference way that will allow me to put the entire operation inside of a loop and reduce the duplication of code that's happening here?
The goal here is that I can use the original variables later on in my code with the updated values. MyVar1, etc, are referenced later on already by legacy code which expects them to be null or have an actual value.
If I understand your question correctly, I don't think what you want to do is possible. Please see this question: Interesting "params of ref" feature, any workarounds?
The only thing I can suggest (which I know doesn't answer your question) is creating a method to avoid duplication of your conditional logic:
void Convert(ref string text)
{
if (string.IsNullOrEmpty(text) || "Blank".Equals(text))
{
text = null;
}
}
You could create a function instead of passing references, which would also be more readable.
string Validate(string inputString)
{
return string.IsNullOrEmpty(inputString) || "Blank".Equals(inputString) ? null : inputString;
}
<...>
MyVar1 = Validate(MyVar1);
Update:
Now I get what you're trying to do. You have a bunch of variables, and you want to perform some sort of bulk operation on them without changing anything else. Putting them in a class isn't an option.
In that case you're really stuck operating on them one at a time. There are ways to shorten it, but you're pretty much stuck with the repetition.
I'd
create a string SanitizeString(string input) function
type x = SanitizeString(x); once for each variable
copy and paste the variable names to replace x.
It's lame, but that's about all there is.
Perhaps this would be a better approach. It ensures that the values are always sanitized. Otherwise you can't easily tell whether the values have been sanitized or not:
public class MyValues
{
private string _value1;
private string _value2;
private string _value3;
public string Value1
{
get { return _value1; }
set { _value1 = Sanitize(value); }
}
// repeat for other values
private string Sanitize(string input) =>
string.IsNullOrEmpty(input) || string.Equals("Blank", input) ? null : input;
}
That's one option. Another is to sanitize the inputs earlier. But ideally we want to ensure that a given class is always in a valid state. We wouldn't want to have an instance of a class whether the values may or may not be valid. It's better to ensure that they are always valid.
ref doesn't really factor into it. We don't need to use it often, if ever. With a value type or string we can just return a new value from a function.
If we're passing a reference type and we want to make changes to it (like setting its properties, adding items to a list) then we're already passing a reference and we don't need to specify ref.
I'd try to write methods first without using ref and only use it if you need to. You probably never will because you'll succeed at whatever you're trying to do without using ref.
Your comment mentioned that this is a legacy app and it's preferable not to modify the existing class. That leaves one more option - reflection. Not my favorite, but when you say "legacy app" I feel your pain. In that case you could do this:
public static class StringSanitizer
{
private static Dictionary<Type, IEnumerable<PropertyInfo>> _stringProperties = new Dictionary<Type, IEnumerable<PropertyInfo>>();
public static void SanitizeStringProperties<T>(T input) where T : class
{
if (!_stringProperties.ContainsKey(typeof(T)))
{
_stringProperties.Add(typeof(T), GetStringProperties(typeof(T)));
}
foreach (var property in _stringProperties[typeof(T)])
{
property.SetValue(input, Sanitize((string)property.GetValue(input)));
}
}
private static string Sanitize(string input)
{
return string.IsNullOrEmpty(input) || string.Equals("Blank", input) ? null : input;
}
private static IEnumerable<PropertyInfo> GetStringProperties(Type type)
{
return type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(property => property.PropertyType == typeof(string) && property.CanRead && property.CanWrite);
}
}
This will take an object, find its string properties, and sanitize them. It will store the string properties in a dictionary by type so that once it has discovered the string properties for a given type it won't have to do it again.
StringSanitizer.SanitizeStringProperties(someObject);
you can simply use a string[] and get the changes back to the caller method like this.
public Main()
{
var myVar1 = "Blank";
var myVar2 = "";
string myVar3 = null;
var myVar4 = "";
string[] dreamDataStructure = new string[] { myVar1, myVar2, myVar3, myVar4 };
}
private void ProcessStrings(string[] list)
{
for(int i = 0; i < list.Length; i++)
{
if (String.IsNullOrEmpty(list[i]) || "Blank".Equals(list[i]))
list[i] = null;
}
}
I see the following code sometimes, and have no idea what the expression is actually testing.
public static void Something(string[] value)
{
if (value is { })
{
DoSomethingElse();
}
}
That's just the empty property pattern in C# 8, meaning the value not null. It matches any value type or reference type. As Panagiotis Kanavos notes in the comments, this is equivalent to the good old value is object check which has been in C# for a long time.
Generally if you were to specify a property, then it would match or not. This esoteric example illustrates that:
if (value is { Length: 2 })
{
// matches any object that isn't `null` and has a property set to a length of 2
}
The property patterns work best and are most clear when comparing with other patterns in cases such as switch expressions.
While Daniel's answer is right, I think it might be useful to add some context about why you may see the empty property pattern in use. Consider this example controller method that needs some validation done:
public async Task<IActionResult> Update(string id, ...)
{
if (ValidateId(id) is { } invalid)
return invalid;
...
}
In the above, ValidateId() could return null or an instance of BadObjectRequestResult. If the former is returned, the validation is successful and moves on to the rest of the body of Update. If the latter is returned, is {} is true (i.e. of course an instance of BadObjectRequestResult is an object), and the validation fails.
Nicely, out of this we've also provided a variable name, invalid, which we can return immediately. Without that we'd need slightly more verbose code.
public async Task<IActionResult> Update(string id, ...)
{
var invalid = ValidateId(id);
if (invalid != null)
return invalid;
...
}
Whether one is more readable or the other is up to the reader, I've just presented one way the empty property pattern can be used.
Is there a better way of doing this -
if (Number.IsNotNullOrEmpty())
{
var status = _Logic.Order(data, Number);
}
else
{
var status = _Logic.Order(data);
}
Signature of the Order method -
Order(Data data, string number = "4a")
I am basically calling the same method in a different way based on if the number is NULL.
Since null is a valid value to be passed to a method, methods will typically have to deal with the possibility themselves that an argument may be null. Usually, you will see something like this then:
public void Example(string arg)
{
if (arg == null)
throw new ArgumentNullException(nameof(arg));
// …
}
That is for the case where passing a null value is not supported. But there is nothign wrong with explicitly allowing a null value to be passed and handling that internally. For example, instead of throwing an exception, you could simply assign a fallback value:
public void Example(string arg)
{
if (arg == null)
arg = "some default";
// …
}
If you cannot modify your method to add such a logic, then you will have to deal with this outside. If you do know the fallback value yourself, then you can simply use one of these many ways:
// null-coalescing operator
_logic.Order(data, number ?? "4a");
// ternary conditional operator
_logic.Order(data, number != null ? number : "4a" );
// adjust the value separately first
if (number == null)
number = "4a";
_logic.Order(data, number);
If you do not know the default value but instead have to rely on the default value that the method signature offers, or if you have to call a separate overload instead (where the second parameter is not used), then you will unfortunately have to use two separate calls for this. So you won’t be able to avoid this:
if (number != null)
_logic.Order(data, number);
else
_logic.Order(data);
Btw. of course, when dealing with strings, sometimes it makes more sense to use string.IsNullOrEmpty instead of a strict null check. I’ve kept this a strict null check to show the general idea. You can of course adjust it as necessary.
If you don't have control over the signature of Order, a simplified way to write your code from the caller's perspective would be to either use the ?? null-coalescing operator:
var status = _Logic.Order(data, Number ?? "4a");
But that only checks for null, so if you want to check for empty as well, you can do:
var status = _Logic.Order(data, string.IsNullOrEmpty(Number) ? "4a" : Number);
But if you do have control over the method, then rather than have an optional parameter (which can cause some problems down the line if modified), another option is to provide different overloads for the method:
public static void Order (Data data)
{
Order(data, "4a");
}
public static void Order (Data data, string number)
{
// Do stuff here
}
Of course this still doesn't prevent someone from passing null in the number field, so at some point you'll have to do some argument validation. This is pretty common in most methods:
public static void Order (Data data, string number)
{
if (data == null) throw new ArgumentNullException(nameof(data));
if (string.IsNullOrEmpty(number)) number = "4a";
// Do stuff here
}
You can use the following solution to assign default values to parameters when passed NULL:
public static void Order (Data data, string number=null)
{
// Do stuff here
}
Assuming you can't refactor the Logic class for some reason, but you need to use its default, you could maybe use this pattern:
_Logic.Order(data, Number.IsNotNullOrEmpty ? Number : DefaultForNumber.Value);
But the implementation for DefaultForNumber is kind of a pain.
static Lazy<string> DefaultForNumber = new Lazy<string>
(
() => typeof(Logic).GetMethod("Order").GetParameters()[1].DefaultValue as string
);
I am hoping that this is a simple question, and it's just my brain that is missing that final link. And if there is another q&a elsewhere, please point me there and close this... but I couldn't find it anywhere.
Here is the gist:
I have a class with a method with optional parameters, something along the lines of
public class Test
{
public void Method(string required, string someoptionalparameter="sometext", string anotheroptionalparameter="someothertext")
{
// do something here with the parameters
}
}
So far, so good.
Now, I am going to instantiate the class and call the method in my code:
...
Test.Method("RequiredString");
and that will work. If I provide optional parameters, it will still work.
But how do I handle a scenario, where I do not know if an optional value is actual provided. So for instance:
...
Test.Method(requiredString,optionalString1,optionalString2);
...
What if I do not know, if the optionalString1 and optionalString2 have a value or not? Do I then need to write an override for every scenario, along the lines of...
if (optionalString1.isEmpty() && optionalString2.isEmpty())
{
Test.Method(requiredString);
}
else if ((!optionalString1.isEmpty() && optionalString2.isEmpty())
{
Test.Method(requiredString, optionalString1);
}
else if...
There has to be another way, and I bet it is simple and I am just having one of those Fridays... Is there something like...
Test.Method(requiredStrinig, if(!optionalString1.isEmpty())...
You should invert the logic - have those optional parameters be null and then do checks in method. So in your case method should be something like:
public void Method(string required, string opt1 = null, string opt2 = null)
{
opt1 = opt1 ?? "some default non-null value if you need it";
opt2 = opt2 ?? "another default value, this one for opt2";
// for those not knowing what it does ?? is basically
// if (opt1 == null) { opt1 = "value"; }
//... rest of method
}
Then calling that method will be easier in outside code and the logic within the method will be able to handle null cases. Outside of method you don't need to worry about those extra parameters, i.e. you can call the method any way you want, like:
Test.Method(requiredString);
Test.Method(requiredString, "something");
Test.Method(requiredString, null, "something else");
Also as #Setsu said in comment you could do this to avoid passing null as second parameter:
Test.Method("required", opt2: "thanks #Setsu");
Use overloads instead, it gives you better semantics and in case you guess the parameters from client code you'd be sure what overload to use, besides, you'll have all the machinery in one place, check out this technique, hope this helps, regards.
class Program {
static void Main(string[] args) {
Work("Hi!");
}
private static void Work(String p1) {
Work(p1, null, null);
}
private static void Work(String p1, String p2) {
Work(p1, p2, null);
}
private static void Work(String p1, String p2, String p3) {
if ( String.IsNullOrWhiteSpace(p2) ) p2 = String.Empty;
if ( String.IsNullOrWhiteSpace(p3) ) p3 = String.Empty;
Console.WriteLine(String.Concat(p1, p2, p3));
}
}
Optional parameters, are, well, optional. They seem to be a way to reduce the number of overloads you have for a method. If you receive all three parameters, you will have to decide if the second or third parameters are empty and need set to their "default" values.
My suggestion is you call your method with three strings and decide in the method if you have to change the values for string two and three. I would probably use a const or readonly instead of the default values.
I am accessing a text/flat file via flat file source: In the Transformation Task I have the Input Column as ZipCode and the Output Alias as: ZipCode. Usage Type: Read/Write:
I created an Ouput Column; tBookName.
The code looks like this:
This is simply an example of the behavior I have observed.
This mostly happens when I try to use certain methods like Trim( or length.
//This gives me an error message:
//Object Not set to instance Of an object
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
string zipCode = (Row.ZipCode.Trim().lenght != 5 ? null : Row.ZipCode.Trim());
}
//This works:
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
if (!string.IsNullOrEmpty(Row.ZipCode))
{
string zipCode = (Row.ZipCode.Trim().lenght != 5 ? null : Row.ZipCode);
}
}
If you explore the autogenerated code, you'll see that ZipCode is not a primitive type, string. Instead it's a complex type/object because the base types don't support nulls, well not gracefully at least.
Instead, what they have chosen to do is to create a simple object that exposes an _IsNull extension/method/something to allow you to test for whether the type is null.
A more idiomatic way of writing your test would be (excluding the fact that I'm not testing for empty). You have a slightly special case since the string types have the isnullorempty and isnullorwhitespace methods to check for this. If you had other primitives to deal with, then you'd become very familiar with the _IsNull check.
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
if (!Row.ZipCode_IsNull))
{
string zipCode = (Row.ZipCode.Trim().length != 5 ? null : Row.ZipCode);
}
}
Sorry to all the .NET developers out there. My terminology is probably horrible dated. Feel free to edit this answer while I go sort my punch cards.