"Object reference not set to an instance of an object" on predicate - c#

I'm trying to find clients which fields have or contain something. Everything works if I hard code predicate, but when I pass predicate it throws a NullReferenceException.
Repo code:
public IEnumerable<Contractor> Find(Func<Contractor, bool> predicate)
{
var test = db.Contractors.Where(x => x.NIP.Contains("7822574676")).ToList(); //this is correct
try
{
return db.Contractors.Where(predicate).ToList(); // this gives exception
}
catch (Exception ex)
{
return null;
}
}
Service code:
public IEnumerable<ContractorShortDataDTO> FindByNIP(string NIP)
{
try {
return Database.Contractors.Find(x => x.NIP.Contains(NIP)).Select(x =>
new ContractorShortDataDTO()
{
NIP = x.NIP,
CompanyName = x.CompanyName,
ID = x.ID
}).AsEnumerable();
} catch(Exception ex) {
return null;
}
}
What is wrong with that code?

Change the type of the argument in the method from
Func<Contractor, bool> predicate
to
Expression<Func<Contractor, bool>> predicate
See also related question Why would you use Expression<Func<T>> rather than Func<T>?

Related

Pass Expression<Func<Type, bool>> as TestCase

Does anyone know how I can parameterize following:
[Test]
void SelectTest(Expression<Func<MyType, bool>> where)
{
try
{
using (var db = new DataConnection("MyData"))
{
where = e => e.Status == Status.New;
var data = db.GetTable<MyType>()
.(where.Compile())
.Select(e => e);
Assert.IsNotEmpty(data);
}
}
catch (Exception)
{
Assert.False(true);
}
}
I tried adding a testcase like this:
[TestCase(e => e.Status == Status.New)]
But I'm getting the following error:
Expression cannot contain anonymous methods or lambda expressions.
What am I missing?
(I'm using linq2db and nunit)
Appearantly I can use NUnits TestCaseSource to pass Funcs.
See Pass lambda to parameterized NUnit test
My Solution:
public class SelectCollection
{
public static IEnumerable<Expression<Func<Evaluation, bool>>> Evaluation
{
get
{
yield return (e) => e.Status == Status.New;
yield return (e) => e.Id == 0;
}
}
}
Used as:
[Test]
[TestCaseSource(typeof(SelectCollection), "Evaluation")]
public void SelectTest(Expression<Func<Evaluation, bool>> where)
You cannot pass complex expressions as test arguments, only constant primitive types are supported.

Try-Catch with fluent expressions

This LINQ query expression fails with Win32Exception "Access is denied":
Process.GetProcesses().Select(p => p.MainModule.FileName)
And this fails with IOException "The device is not ready":
DriveInfo.GetDrives().Select(d => d.VolumeLabel)
What is the best way to filter out inaccessible objects and avoid exceptions?
Write an extension method!
void Main()
{
var volumeLabels =
DriveInfo
.GetDrives()
.SelectSafe(dr => dr.VolumeLabel);
}
// Define other methods and classes here
public static class LinqExtensions
{
public static IEnumerable<T2> SelectSafe<T,T2>(this IEnumerable<T> source, Func<T,T2> selector)
{
foreach (var item in source)
{
T2 value = default(T2);
try
{
value = selector(item);
}
catch
{
continue;
}
yield return value;
}
}
}
This way you can customise any behaviour you want, and you don't have to create bulky and hacky where clauses, this way you could even get it to return an alternative value if there's an exception.
Update based upon comments: This solution does not work with common enumerators. It does work based upon the enumerators used in the question's examples. Therefore it is not a generic solution. Because it has been written as a generic solution , I advise against using this (to keep things simple). I will keep this answer to enrich the knowledge base.
Another Extension method solution. Why do I prefer it over the existing solutions?
We want to skip elements causing exceptions only. This is the single concern of our LINQ extension.
This implementation does not mix the concern(s) of Select and try/catch.
We can still use existing LINQ methods like Select when needed.
It is reusable: it allows for multiple usages inside a LINQ query.
It follows linq naming conventions: We actually skip similar to Skip and SkipWhile methods.
Usage:
var result = DriveInfo
.GetDrives()
.Select(d => d.VolumeLabel)
.SkipExceptions() // Our extension method
.ToList();
Code:
public static class EnumerableExt
{
// We use the `Skip` name because its implied behaviour equals the `Skip` and `SkipWhile` implementations
public static IEnumerable<TSource> SkipExceptions<TSource>(this IEnumerable<TSource> source)
{
// We use the enumerator to be able to catch exceptions when enumerating the source
using (var enumerator = source.GetEnumerator())
{
// We use a true loop with a break because enumerator.MoveNext can throw the Exception we need to handle
while (true)
{
var exceptionCaught = false;
var currentElement = default(TSource);
try
{
if (!enumerator.MoveNext())
{
// We've finished enumerating. Break to exit the while loop
break;
}
currentElement = enumerator.Current;
}
catch
{
// Ignore this exception and skip this item.
exceptionCaught = true;
}
// Skip this item if we caught an exception. Otherwise return the current element.
if (exceptionCaught) continue;
yield return currentElement;
}
}
}
}
Your answer is the correct one. You can of course try to hide the checking logic inside an extension method.
public static IEnumerable<TElement> WhereSafe<TElement, TInner>(this IEnumerable<TElement> sequence, Func<TElement, TInner> selector)
{
foreach (var element in sequence)
{
try { selector(element); }
catch { continue; }
yield return element;
}
}
Process
.GetProcesses()
.WhereSafe(p => p.MainModule)
.Select(p => p.MainModule.FileName)
Or better so:
public static IEnumerable<TInner> TrySelect<TElement, TInner>(this IEnumerable<TElement> sequence, Func<TElement, TInner> selector)
{
TInner current = default(TInner);
foreach (var element in sequence)
{
try { current = selector(element); }
catch { continue; }
yield return current;
}
}
Process
.GetProcesses()
.TrySelect(p => p.MainModule.FileName)
Insert a WHERE filter (that tries to access any object and absorbs the possible access error) with:
{ try { var x = obj.MyProp; return true; } catch { return false; } }:
First expression:
Process
.GetProcesses()
.Where(p => { try { var x = p.MainModule; return true; } catch { return false; } })
.Select(p => p.MainModule.FileName)
Second expression:
DriveInfo
.GetDrives()
.Where(d => { try { var x = d.VolumeLabel; return true; } catch { return false; } })
.Select(d => d.VolumeLabel)
I would try for the first scenario:
//Declare logger type
private readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
Process.GetProcesses()
.Where(p => {
try {
var x = p.MainModule;
return true;
}
catch(Win32Exception e2)
{ IgnoreError(); }
})
.Select(p => p.MainModule.FileName)
public static void IgnoreError(Exception e)
{
#if DEBUG
throw e2;
//Save the error track, I prefer log4net
_log.Info("Something bad happened!");
#end if
}
And for the second scenario, I'd rather prefer to use an IF and save the log:
//Somewhere in the begging of your class, in a place whose name I do not care to remember ...
//Declare logger type
private readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public List<string> VolumenLabels()
{
//Return the List<T>
List<string> myVolumeLabels = new List<string>();
//Getting the info
DriveInfo[] allDrives = DriveInfo.GetDrives();
foreach(DriveInfo drive in allDrives)
{
if (drive.IsReady == true)
{
myVolumeLabels.Add(drive.VolumeLabel.ToString());
}
else
{
_log.Info("Check the Drive: " + drive.Name + " the device is not ready.");
}
}
return myVolumeLabels;
}
I hope, I helped a little bit... Have a nice day!

Return a List<string> with a linq compiled query

I'm creating a compiled linq to sql query based on the tutorial here and I'm trying to figure out how to return the results as a list so I can use the results in my code. Currently it is the default IEnumerable and I get the error that it can't be enumerated twice.
public static Func<OoplesDBDataContext, string, IEnumerable<string>> GetValidSymbols
{
get
{
Func<OoplesDBDataContext, string, IEnumerable<string>> func =
CompiledQuery.Compile<OoplesDBDataContext, string, IEnumerable<string>>
((OoplesDBDataContext context, string market) =>
from c in context.Symbols
where c.Market == market && c.isActive == true && c.isUnderReview == false
select c.Symbol1);
return func;
}
}
public static List<string> getStockSymbols(string market)
{
List<string> symbolList = new List<string>();
try
{
using (OoplesDBDataContext context = new OoplesDBDataContext())
{
context.ObjectTrackingEnabled = false;
var query = QueriesUtility.GetValidSymbols(context, market);
return query.ToList(); // breaks here with the error
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return null;
}

The best way to throw an exception

Do you know a better way (more pretty) than below to throw an exception?
public long GetPlaylistId(long songInPlaylistId)
{
var songInPlaylist = service.GetById(songInPlaylistId);
return songInPlaylist
.With(x => x.Playlist)
.ReturnValueOrException(x => x.Id,
new ArgumentException(
"Bad argument 'songInPlaylistId'"));
}
Monadic extension methods:
public static TResult With<TInput, TResult>(this TInput obj,
Func<TInput, TResult> evaluator)
where TInput : class
where TResult : class
{
return obj == null ? null : evaluator(obj);
}
public static TResult ReturnValueOrException<TInput, TResult>(
this TInput obj, Func<TInput, TResult> evaluator, Exception exception)
where TInput : class
{
if (obj != null)
{
return evaluator(obj);
}
throw exception;
}
If it is valid to try to get the playlist for something that doesn't have a playlist, then you should not throw an exception but should just return a special value that means "not found" instead (for example, 0 or -1 depending on how your playlist IDs work).
Alternatively you could write a TryGetPlaylistId() method which works in a similar way to Microsoft's TryXXX() methods (e.g. SortedList.TryGetValue()), for example:
public bool TryGetPlaylistId(long songInPlaylistId, out long result)
{
result = 0;
var songInPlaylist = service.GetById(songInPlaylistId);
if (songInPlaylist == null)
return false;
if (songInPlaylist.Playlist == null)
return false;
result = songInPlaylist.Playlist.Id;
return true;
}
A small problem with this approach is that you are obscuring information that might be of use when trying to diagnose issues. Perhaps adding Debug.WriteLine() or some other form of logging would be of use. The point being, you can't differentiate between the case where the playlist ID is not found, and the case where it is found but doesn't contain a playlist.
Otherwise, you could throw an exception which has a more informative message, for example:
public long GetPlaylistId(long songInPlaylistId)
{
var songInPlaylist = service.GetById(songInPlaylistId);
if (songInPlaylist == null)
throw new InvalidOperationException("songInPlaylistId not found: " + songInPlaylistId);
if (songInPlaylist.Playlist == null)
throw new InvalidOperationException("Playlist for ID " + songInPlaylistId " has no playlist: ");
return songInPlaylist.Playlist.Id;
}
It might be the case that it is valid to not find the song in the playlist, but it is NOT valid to find one which does not have a playlist, in which case you would return a special value in the first case and throw an exception in the second case, for example:
public long GetPlaylistId(long songInPlaylistId)
{
var songInPlaylist = service.GetById(songInPlaylistId);
if (songInPlaylist == null)
return -1; // -1 means "playlist not found".
if (songInPlaylist.Playlist == null)
throw new InvalidOperationException("Playlist for ID " + songInPlaylistId " has no playlist: ");
return songInPlaylist.Playlist.Id;
}
In any case, I personally think that your extension methods are just obscuring the code.
try{
if (obj != null)
{
return evaluator(obj);
}
}
catch(Exception ex)
{
throw;
}
return obj;
You should not throw error unless caught in to some. Better return null in the given case and handle it in your calling code:
And what will happen if I have more than one such ambiguous methods in my class? It's very difficult to invent different rules for any method. You will be confused in the end.
What do you think about this solution?
public class ApplicationResponse
{
public IList<string> Errors { get; set; }
public dynamic Data { get; set; }
public bool HasErrors()
{
return Errors != null && Errors.Any();
}
}
public ApplicationResponse GetPlaylistId(long songInPlaylistId)
{
var songInPlaylist = service.GetById(songInPlaylistId);
if (songInPlaylist == null)
{
return new ApplicationResponse { Errors = new[] { "Song was not found." } };
}
if (songInPlaylist.Playlist == null)
{
return new ApplicationResponse { Errors = new[] { "Playlist was not found." } };
}
return new ApplicationResponse { Data = songInPlaylist.Playlist.Id };
}
public HttpResponseMessage SomeRequest([FromUri] songInPlaylistId)
{
var response = appService.GetPlaylistId(long songInPlaylistId);
if (response.HasErrors())
{
// reply with error status
}
// reply with ok status
}
In such case I can send all the errors to a client.

Can Expression<Func<T,object>> and destination.x=source.x be refactored?

I'm generating an interface to concrete implementation copier. A later step will be to determine if I can easily add varying behaviors depending on the copy type requested (straight copy, or try, or try-catch-addToValidationDictionary). This is the main one I need/am working on is the try-catch-addToValidationDictionary. It would be lovely if the copy statements themselves(result.AssetTag = asset.AssetTag) were reusable in list form for another consumer that doesn't need the try/catch/validation functionality.
The General form is this:
public static AssetService
{
public static ModelAsset CreateAssetDomain(IAmAnAsset asset, IValidationDictionary validationDictionary)
{
var result=new ModelAsset();
var hasExceptions=false;
try
{
result.AssetTag = asset.AssetTag;
}
catch (System.Exception exception)
{
validationDictionary.AddError(Member.Name<IAmAnAsset>(lIAmAnAsset => lIAmAnAsset.AssetTag), exception.Message);
hasExceptions = true;
}
try
{
result.LocationIdentifer = asset.LocationIdentifer;
}
catch (System.Exception exception)
{
validationDictionary.AddError(Member.Name<IAmAnAsset>(lIAmAnAsset => lIAmAnAsset.LocationIdentifer), exception.Message);
hasExceptions = true;
}
...
if (hasExceptions)
throw new ArgumentException("Failed validation");
return result;
}
}
I'm trying to factor out some of the repetition with lambdas but the Member.Name<IAmAnAsset>(lIAmAnAsset => lIAmAnAsset.AssetTag) from this post seems to only take an Expression<Func<T,object>> and I'm not sure how you would make use of the Expression> overload.
One attempt was as follows:
Action<Action, Expression<Func<IAmAnAsset, object>>> CopyActions = (copyAction, expression) =>
{
try
{
copyAction();
}
catch (Exception exception)
{
validationDictionary.AddError(Member.Name<IAmAnAsset>(expression), exception.Message);
hasExceptions = true;
}
};
var copyActions = new Dictionary<string,Action>()
{
Member.Name<IAmAnAsset>(z=>z.AddedBy),()=>result.AddedBy=asset.AddedBy},
Member.Name<IAmAnAsset>(z=>z.AssetTag),()=>result.AssetTag=asset.AssetTag},
...
}
foreach (var item in copyActions)
{
tryCopyAction(item.Value, item.Key);
}
if (hasExceptions)
throw new ArgumentException("Failed validation");
return result;
I'm hoping for a solution that reduces the duplication inherent in
Member.Name<IAmAnAsset>(z=>z.AddedBy),()=>result.AddedBy=asset.AddedBy},
on any of the following criteria:
needing the IAmAnAsset.AddedBy in 2 places on each line
needing .AddedBy 3 times on the same line
Member.Name<IAmAnAsset> on each and every line
Is it possible to have this Expression utilized to retrieve either the string name, or the value of evaluating it?
How about a simple function?
public static class Member
{
private static string GetMemberName(Expression expression)
{
switch (expression.NodeType)
{
case ExpressionType.MemberAccess: var memberExpression = (MemberExpression)expression; var supername = GetMemberName(memberExpression.Expression); if (String.IsNullOrEmpty(supername)) return memberExpression.Member.Name; return String.Concat(supername, '.', memberExpression.Member.Name);
case ExpressionType.Call: var callExpression = (MethodCallExpression)expression; return callExpression.Method.Name;
case ExpressionType.Convert: var unaryExpression = (UnaryExpression)expression; return GetMemberName(unaryExpression.Operand);
case ExpressionType.Parameter: return String.Empty;
default: throw new ArgumentException("The expression is not a member access or method call expression");
}
}
public static string Name<T,V>(Expression<Func<T, V>> expression)
{
return GetMemberName(expression.Body);
}
public static string Name<T>(Expression<Action<T>> expression)
{
return GetMemberName(expression.Body);
}
}
void Copy<D, S, V>(D dest, S source, Expression<Func<S, V>> getVal, Action<D, V> setVal, IDictionary validationDictionary)
{
Func<S, V> doGetVal = getVal.Compile();
try { setVal(dest, (V)doGetVal(source)); }
catch (System.Exception exception)
{
validationDictionary.Add(Member.Name<S,V>(getVal), exception.Message);
}
}
class TestAsset { public string AssetTag { get; set; } public string LocationIdentifier { get; set; } }
TestAsset Test()
{
Dictionary<string, string> validationDictionary = new Dictionary<string, string>();
var result = new TestAsset{ AssetTag = "a", LocationIdentifier = "b" };
var asset = new TestAsset{ AssetTag = "A", LocationIdentifier = "B" };
var validationCount = validationDictionary.Count();
Copy(result, asset, x => asset.AssetTag, (x, v) => x.AssetTag = v, validationDictionary);
Copy(result, asset, x => asset.LocationIdentifier, (x, v) => x.LocationIdentifier = v, validationDictionary);
if (validationCount < validationDictionary.Count) throw new ArgumentException("Failed validation");
return result;
}

Categories

Resources