I've been trying to figure out how I could use the Maybe monad in iSynaptic.Commons in a context where my value retriever could throw an exception:
For example:
dynamic expando = new Expando();
expando.Name = "John Doe";
var maybe = Maybe.Defer(()=>(string)expando.NonExistingProperty);
//In this context I would like the exception which is thrown
//to result in Maybe<string>.NoValue;
if(maybe.HasValue) {
//Do something
}
Is this possible with the implementation of maybe that is out there
There are several ways of using iSynaptic.Commons to allow an exception. Each way I found requires the .Catch() extension method to let the monad know to silently catch the exception. Also, be careful when accessing the property maybe.Value. If this property is Maybe.NoValue, an InvalidOperationException will be thrown.
1) Create a "OnExceptionNoValue" extension method. This will check the Maybe to see if it has an exception. If it does, a NoValue Maybe will be returned. Otherwise the original Maybe will be returned.
public static class MaybeLocalExtensions
{
public static Maybe<T> OnExceptionNoValue<T>(this Maybe<T> maybe)
{
return maybe.Exception != null ? Maybe<T>.NoValue : maybe;
}
}
// Sample Use Case:
var maybe = Maybe.Defer(() => (string)expando.NonExistingProperty).Catch()
.OnExceptionNoValue();
2) Create a "BindCatch" extension method. This changes the behavior of the normal bind when an exception is present to return Maybe.NoValue instead of throwing an exception.
public static class MaybeLocalExtensions
{
public static Maybe<TResult> BindCatch<T, TResult>(this Maybe<T> #this, Func<T, Maybe<TResult>> selector)
{
var self = #this;
return new Maybe<TResult>(() => {
if (self.Exception != null)
return Maybe<TResult>.NoValue;
return self.HasValue ? selector(self.Value) : Maybe<TResult>.NoValue;
});
}
}
// Sample Use Case:
var maybe = Maybe.Defer(() => (string)expando.NonExistingProperty).Catch()
.BindCatch(m => m.ToMaybe());
3) This way also uses the Catch() extension method, but uses the maybe.HasValue property instead of relying on extension methods. If an exception is present in the Maybe, the HasValue property is false. When this value is false, the Maybe.NoValue can replace the value of the variable maybe or whatever needs to be done in this case.
dynamic expando = new ExpandoObject();
expando.Name = "John Doe";
// This example falls to the else block.
var maybe = Maybe.Defer(() => (string)expando.NonExistingProperty).Catch();
//In this context I would like the exception which is thrown
//to result in Maybe<string>.NoValue;
if (maybe.HasValue) {
//Do something
Console.WriteLine(maybe.Value);
} else {
maybe = Maybe<string>.NoValue; // This line is run
}
// This example uses the if block.
maybe = Maybe.Defer(() => (string)expando.Name).Catch();
//to result in Maybe<string>.NoValue;
if (maybe.HasValue) {
//Do something
Console.WriteLine(maybe.Value); //This line is run
} else {
maybe = Maybe<string>.NoValue;
}
These answers are all variations on the same theme, but I hope they are helpful.
Related
I'm running into an odd scenario that doesn't happen on my PC, but does for a coworkers.
I have this piece of code:
LoaderHelpers.SetStringValue<blah>(this, "x", $"x response in Header",
() => jsonData.x.response[0].value, false);
The problem is that sometimes, "jsonData.x" is null and, for my coworker a 'cannot bind to null at runtime exception' is thrown, but not for me there isn't. I have code to handle the null scenario, but it's like his code never gets to that point and fails at the call level.
jsonData is of type dynamic.
The method code that handles the null scenario:
public static void SetStringValue<T>(IValidate data, string propertyName,
string valuePath, Func<string> value, bool required)
{
if (data.GetType().GetProperty(propertyName) != null)
{
try
{
if (string.IsNullOrEmpty(value()))
{
if (required)
data.DataValidationErrors.Add($"{valuePath} can't be empty");
data.GetType().GetProperty(propertyName).SetValue(data, null);
}
else
{
data.GetType().GetProperty(propertyName).SetValue(data, value());
}
}
catch
{
//property doesn't exist
if (required)
data.DataValidationErrors.Add($"{valuePath} doesn't exist");
data.GetType().GetProperty(propertyName).SetValue(data, null);
}
}
else
{
throw new NullReferenceException($"In {data.GetType()} => SetStringValue. " +
$"Passed property {propertyName}, but property doesn't exist.");
}
}
Again. Works perfect for me, but not for him. I'm completely lost. Maybe I don't understand how the lamba/function parameters work 100%, but I thought it only got evaluated when value() is invoked.
I should also mention that when I debug this code, I can step into the Nuget package and when he hits the same line, he can't. This maybe a useful hint.
If jsonData (or jsonData.x) is null (as it seems to be at this point) it will crash and give you that error every time you call the method value().
You need to check why jsonData.x is null. Maybe it´s a race condition caused by another thread setting this value to null, maybe it´s because a bad jsonData initialization... Can´t say since that code is not here.
There are so many things wrong with your code, i can't resist.
First of all, instead of copy/pasting the same stuff over and over, you might want to use a variable:
var property = data.GetType().GetProperty(propertyName);
Second, you pass a Func<string> and execute it multiple times, why is it even a function then? Yet again, better only evaluate it once and use a variable...
var unwrapped = value();
That would solve the issue, that Roberto Vázquez' answer adresses.
Then you are misusing NullReferenceException, instead rather use a ArgumentException
Next issue, that valuePath is only used in the exception message, that is a poor design to my beliefs.
The generic T parameter isnt even used, so get rid of it.
Last but not least, that catch-block doing the exact thing that could possibily throw the exception again, i cant see any reason why you would do this.
Finnaly this whole thing becomes a little more clear but its still a mess.
public static void SetStringValue(IValidate data, string propertyName,
string valuePath, Func<string> value, bool required)
{
if(data == null)
throw new ArgumentNullException(nameof(data));
var property = data.GetType().GetProperty(propertyName);
if(property == null)
throw new ArgumentException($"In {data.GetType()} => SetStringValue. " +
$"Passed property {propertyName}, but property doesn't exist.");
var unwrapped = value();
try
{
if (string.IsNullOrEmpty(unwrapped))
{
if (required)
data.DataValidationErrors.Add($"{valuePath} can't be empty");
unwrapped = null; // this might be unecessary.
}
property.SetValue(data, unwrapped);
}
catch(Exception e)
{
// This is probably a bad idea.
property.SetValue(data, null);
if (required)
data.DataValidationErrors.Add(Atleast put a better message here. e.Message ...);
}
}
I have the following code, the idea is simple if the object is in cache get it, if not then retrieve it from the data source and save it into cache, I am using resharper and I got this warning but cant understand why
public static ModulosPorUsuario GetModulesForUser(string identityname)
{
// It needs to be cached for every user because every user can have different modules enabled.
var cachekeyname = "ApplicationModulesPerUser|" + identityname;
var cache = CacheConnectionHelper.Connection.GetDatabase();
ModulosPorUsuario modulosUsuario;
//get object from cache
string modulosUsuariosString = cache.StringGet(cachekeyname);
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
if (modulosUsuariosString != null)
{
//conver string to our object
modulosUsuario = JsonConvert.DeserializeObject<ModulosPorUsuario>(modulosUsuariosString);
return modulosUsuario;
}
// ReSharper disable once HeuristicUnreachableCode
modulosUsuario = DbApp.ModulosPorUsuario.Where(p => p.Email == identityname).FirstOrDefault();
//convert object to json string
modulosUsuariosString = JsonConvert.SerializeObject(modulosUsuario);
//save string in cache
cache.StringSet(cachekeyname, modulosUsuariosString, TimeSpan.FromMinutes(SettingsHelper.CacheModuleNames));
return modulosUsuario;
}
There's quite a lot going on here, but the bottom line, this is a ReSharper bug - the value can certainly be null, and I have a much smaller example proving it.
First, let's figure out what's going on in your code. I had to dig a little bit into the StackExchange.Redis library that you're using. Your cache object is, in fact, an IDatabase, which is implemented by the RedisDatabase class. The StringGet method that you're using returns a RedisValue, which is a struct. This, by itself, would make perfect sense why ReSharper tells you it can never be null - value types can't!
However, you're putting the result into a string variable! This works because the RedisValue struct defines a bunch of implicit operators to convert the value into the requested type. In case of a string, notice that if the blob is empty, an empty string is returned:
RedisValue.cs
/// <summary>
/// Converts the value to a String
/// </summary>
public static implicit operator string(RedisValue value)
{
var valueBlob = value.valueBlob;
if (valueBlob == IntegerSentinel)
return Format.ToString(value.valueInt64);
if (valueBlob == null) return null;
if (valueBlob.Length == 0) return "";
try
{
return Encoding.UTF8.GetString(valueBlob);
}
catch
{
return BitConverter.ToString(valueBlob);
}
}
But from this code it's obvious that the string can be null as well.
This makes ReSharper incorrect to flag that line, and it can be reproduced with a smaller example:
static void Main(string[] args)
{
string value = MyStruct.GetValue();
if (value == null) // <- ReSharper complains here, but the value is null!
{
return;
}
}
public struct MyStruct
{
public static MyStruct GetValue() => new MyStruct();
public static implicit operator string(MyStruct s)
{
return null;
}
}
I reported this issue to JetBrains, they will fix it.
In the meantime, you might want to keep that comment, disabling ReSharper warning.
I like using implicit typing for almost everything because it's clean and simple. However, when I need to wrap a try...catch block around a single statement, I have to break the implicit typing in order to ensure the variable has a defined value. Here's a contrived hypothetical example:
var s = "abc";
// I want to avoid explicit typing here
IQueryable<ABC> result = null;
try {
result = GetData();
} catch (Exception ex) { }
if (result != null)
return result.Single().MyProperty;
else
return 0;
Is there a way I can call GetData() with exception handling, but without having to explicitly define the type of the result variable? Something like GetData().NullOnException()?
This is a common problem. I recommend that you just stick with your existing solution.
If you really want an alternative, here it is:
static T NullOnException<T>(Func<T> producer) where T : class {
try { return producer(); } catch { return null; } //please modify the catch!
}
//now call it
var result = NullOnException(() => GetData());
Please modify this to log the exception or restrict the catch to a concrete type. I do not endorse swallowing all exceptions.
As this answer is being read a lot I want to point out that this implementation is just of demo-quality. In production code you probably should incorporate the suggestions given in the comments. Write yourself a robust, well-designed helper function that will serve you well for years.
Just put your code inside the try:
var s = "abc";
// I want to avoid explicit typing here
try {
var result = GetData();
if (result != null)
return result.Single().MyProperty;
else
return 0;
} catch (Exception ex) { }
I came to a similar solution as #usr, but with slightly different semantics:
T LiftScope<T>(Func<T> ScopedFunction)
{
T result = ScopedFunction();
return result;
}
The purpose of LiftScope is to carry an internal variable out to the caller without compromising implicit typing. This could be used to solve the original problem, except that the try...catch would actually be embedded in the call.
try...catch
var result =
LiftScope(() => {
try { return producer(); } catch { return null; }
});
Now the caller is able to be responsible for exception handling. Furthermore, this can be used generically in a handful of similar use-cases where you have very short-lived scopes.
if
var result =
LiftScope(() => {
if (a == b)
return GetData(true);
else if (b == c)
return GetData(false);
else
return GetData(true, 2);
});
This could also be solved with a ternary-style if statement.
using
var result =
LiftScope(() => {
using (var myContext = new MyDataContext())
{
return myContext.MyTable.Where(w => w.A == B).ToList();
}
});
How do I know the log the last property that is null?
For example,
var a = "somevalue";
......
......
if(a == null)
{
Log.Error(MethodBase.GetCurrentMethod().Name + "Property : a is null");
//blah blah
}
Like how I use the reflection to get the current method name, there should be some means by which I can log the latest local variables (or a property or fields)
that is being compared ? I use, log4net by the way to log the errors.
1) Is there any method to achieve this or should we manually log it?
2) Is there any custom method that prints the class -> MethodName -> Propertyname(or FieldName) that is null?
Thanks for your time in advance.
As mentioned by #fsimonazzi, "a" would be a local variable.
That being said there is still no way to examine the current compare operation as in MSIL there is no formal concept of an IF block - only conditional jumps.
If you wanted to get really crazy with the reflection, you may be able to find the current executing instruction and look around near that for a variable, but even then, you will not find the name - only a reference - as names are only used prior to compilation.
Either way, reflection is not going to help you here.
Instead, try using Exceptions - specifically ArgumentNullException. This body of code would become:
void doStuff(string param1, int param2)
{
if (param == null)
throw new ArgumentNullException("param1", "param1 must not be null");
if (param2 < 0)
throw new ArgumentOutOfRangeException("param2", "param2 should be non-negative.");
//method body
}
then, when you call the method, you can catch the exception and log it - no matter what it may be.
public static void Main(string[] args)
{
try
{
doStuff(null, 3);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
Tools like FxCop can help make sure that you are properly validating each parameter.
Properties are actually implemented as methods, so reflection could help you there. If, for example, you were validating in a property and wanted to log the position automatically, you could.
private object _cachedObject = null;
public object CachedObject
{
get
{
if (_cachedObject == null)
{
log(MethodBase.GetCurrentMethod().Name, "creating cached object");
_cachedObject = createCachedObject();
}
return _cachedObject;
}
}
The .Net Framework 4.5 also brings with it a new attribute that can be used to replace the MethodBase.GetCurrentMethod().Name construct you are using to get the method name. See [CallerMemberNameAttribute][3].
I have to create a bunch of methods that look like this. The things that change will be the method name, the return type and the lines marked in the middle - the rest will be the same. Is there a clean way to refactor this so that I don't repeat myself?
private bool CanPerform(WindowsIdentity identity, string applicationName, int operation)
{
IAzApplication3 application = null;
IAzClientContext3 context = null;
try
{
application = this.store.OpenApplication(applicationName, null) as IAzApplication3;
ulong token = (ulong)identity.Token.ToInt64();
context = application.InitializeClientContextFromToken(token, null) as IAzClientContext3;
// lines that change go here
}
catch (COMException e)
{
throw new SecurityException(string.Format("Unable to check operation '{0}'", operation), e);
}
finally
{
Marshal.FinalReleaseComObject(context);
Marshal.FinalReleaseComObject(application);
}
}
I realise this is probably basic stuff but I work alone so there's no one else to ask.
It sounds like a delegate would be appropriate here, with a generic method to cover the return type changing:
private T ExecuteWithIdentity<T>(WindowsIdentity identity,
string applicationName, int operation,
Func<IAzApplication3, IAzClientContext3, T> action)
{
IAzApplication3 application = null;
IAzClientContext3 context = null;
try
{
application = this.store.OpenApplication(applicationName, null) as IAzApplication3;
ulong token = (ulong)identity.Token.ToInt64();
context = application.InitializeClientContextFromToken(token, null) as IAzClientContext3;
return action(application, context);
}
catch (COMException e)
{
throw new SecurityException(
string.Format("Unable to check operation '{0}'", operation), e);
}
finally
{
Marshal.FinalReleaseComObject(context);
Marshal.FinalReleaseComObject(application);
}
}
Then you put the code for each check in a separate method, or even just use a lambda expression:
bool check = ExecuteWithIdentity(identity, "Foo", 10,
(application, context) => context != null);
or
string check = ExecuteWithIdentity(identity, "Foo", 10, SomeComplexAction);
...
private static string SomeComplexAction(IAzApplication3 application,
IAzClientContext3 context)
{
// Do complex checks here, returning whether the user is allowed to
// perform the operation
}
You may want to change the delegate type of course - it's not clear what operation is meant to be used for, for example.
I would also strongly consider casting instead of using as. If the application or context is returned from OpenApplication/InitializeClientContextFromTokenas a non-null value which just isn't the right type, do you really want to handle that the same was as a null value being returned?
You could do your error handling slightly higher up the stack, so rather than catching and rethrowing the exception inside the method you could do it where the method is called?
If your method calls are all wrapped in a Manager class that might save a bit of time. If they're just ad-hoc called everywhere then naturally maybe not :)
I hope that might help.