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.
Related
I'm trying to understand a way to pass in two or more extension methods to a another method as parameters and return the value back. I have extension methods for each datatype to return a value or default value and a value or a null value and also a value or throw an error. The code has scenarios that would require each of these, but it also has scenarios combining the results from each of these in a ternary test, examples below.
public static int IntOrError(this object val, string fieldName)
{
int test;
if (string.IsNullOrEmpty(val.ToString()))
{
throw new Exception("I threw it");
}
else if (int.TryParse(val.ToString(), out test) == false)
{
throw new Exception("Bad Int Value");
}
else
{
return test;
}
}
public static int IntOrDefault(this object val)
{
int test;
if (int.TryParse(val.ToString(), out test))
{
return test;
}
else
{
return -1;
}
}
public static int? IntOrNull(this object val)
{
int test;
if (int.TryParse(val.ToString(), out test))
{
return test;
}
else
{
return -1;
}
}
I've been trying to make a reusable method that could process taking in in this example IntOrNull, IntOrDefault and IntOrError and pass back the int or throw an error. So far I've only been able to get this to work. I'm trying to avoid creating this method for every datatype also.
public static int IntDefaultValidated(this object val, string fieldName)
{
return val.IntOrNUll() != null
? val.IntOrDefaultError(fieldName)
: val.IntOrDefault();
}
I am trying to get a generic method or a functional style of method that will take in the extension methods as params and return back the value.
I'm hoping to avoid reflection if possible.
//just a psuedo example
var intVal = "";
var valRet = DefaultValidated(intVal.IntOrNull(), intVal.IntOrdefault(), intVal.IntOrDefaultError("intVal"));
//or maybe like this, or some combination of extension, generic, functional
var valRet = intVal.DefaultOrValidated(IntOrNull(intVal), IntOrDefault(intVal), IntOrDefaultError(intVal, "intVal"));
Your logic of IntOrDefault, IntOrNull and IntDefaultValidated does not really make sense, so I think it's just an usage example.
Beside this - my advice is to implement your functions as generic extensions.
public static class MyExtensions
{
public static T ValueOrError<T>(this object val)
{
try
{
// http://stackoverflow.com/a/8633/2534462
return (T)Convert.ChangeType(val, typeof(T));
} catch
{
throw new Exception("Throw your own exception if you really want to");
}
}
public static T ValueOrDefault<T>(this object val, T defaultValue)
{
try
{
return val.ValueOrError<T>();
}
catch
{
return defaultValue; // usally use: return default(T);
}
}
public static T ValueOrNull<T>(this object val)
{
try
{
return val.ValueOrError<T>();
}
catch
{
// check for nullable type
//https://msdn.microsoft.com/de-de/library/ms366789.aspx
var type = typeof(T);
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
return default(T); // null on nullable types
} else {
throw new Exception("Callable only on Nullable types");
// my return another default value ??? .. -1 ???
}
}
}
public static T ValueDefaultValidated<T>(this object val, T defaultValue)
{
return val.ValueOrNull<T>() != null
? val.ValueOrError<T>()
: val.ValueOrDefault<T>(defaultValue);
}
}
Usage
string aNumber = "10";
var intNumber = aNumber.ValueDefaultValidated(-1); // int
var decNumber = aNumber.ValueDefaultValidated(-1m); // decimal
string naNumber = "whatever";
var defaultInt = naNumber.ValueOrDefault(-1); // int
var defaultDecimal = naNumber.ValueDefaultValidated<decimal?>(-1m);
// ValueOrNull ist undefined on Non-Nullable-Type.
var undefined = naNumber.ValueDefaultValidated<decimal>(-1m);
Something like this?
public static T Convert<T>(this object input)
{
if (typeof (T) == input.GetType())
return (T) input;
var stringValue = input.ToString();
var converter = TypeDescriptor.GetConverter(typeof(T));
if (converter.CanConvertFrom(typeof(string)))
{
return (T)converter.ConvertFrom(stringValue);
}
return default(T);
}
This test passes. May be this is not exactly what you need but still.
[Fact]
public void TestMethod1()
{
object testInt = 1;
object testString = "123";
double testDouble = 1.0;
string testWrong = "abc";
int resultInt = testInt.Convert<int>();
string resultString = testString.Convert<string>();
int resultIntString = testString.Convert<int>();
int dbl2int = testDouble.Convert<int>();
Assert.Throws<Exception>(() => testWrong.Convert<int>());
Assert.Equal(1, resultInt);
Assert.Equal("123", resultString);
Assert.Equal(123, resultIntString);
Assert.Equal(1, dbl2int);
}
I am obviously doing something wrong here, but the question is how do i get it working? I got the following code
Note: ParameterEventStreamRef inherits from Parameter, same goes for the StStvariants.
public void DoStuff(Parameter[] parameters)
{
var Parameters = parameters.Select(x => parameterConverterFactory.GetParameterConverter(x).ToJsonClass(x)).ToArray();
}
public class ParameterConverterFactory: IParameterConverterFactory
{
public IStackStateJsonConverter<StStParameter, Parameter> GetParameterConverter(StStParameter arg)
{
if (arg.GetType() == typeof(StStParameterEventStreamRef))
return new JsonParameterEventStreamRefConverter();
throw new InvalidEnumArgumentException(arg.GetType().FullName);
}
public class JsonParameterEventStreamRefConverter : JsonParameterConverter, IStackStateJsonConverter<StStParameterEventStreamRef, ParameterEventStreamRef>
{
public ParameterEventStreamRef ToJsonClass(StStParameterEventStreamRef arg, ParameterEventStreamRef source = null)
{
if (source == null)
source = new ParameterEventStreamRef();
base.ToJsonClass(arg, source);
source.var1 = arg.var1;
source.var2 = arg.var2;
return source;
}
}
public class JsonParameterConverter : JsonNodeConverter, IStackStateJsonConverter<StStParameter, Parameter>
{
public Parameter ToJsonClass(StStParameter arg, Parameter source = null)
{
if (source == null)
source = new Parameter();
source.var0 = arg.var0;
return source;
}
}
Problem is: the factory is returning the correct Converter, but when the converter is called, it is "Skipping" the JsonParameterEventStreamRefConverter and going directly to the JsonParameterConverter. I think the reason for this is a part of the logic is done compile-time, the other run-time.
In DoStuff() you're calling the ToJsonClass() method. Even though that you 'x' could be any descendant from Parameter, the runtime will not know which one it is.
It will look for the ToJsonClass() signature that best matches the signature: ToJsonClass(Parameter). The JsonParamterConverter has a method that matches this exactly, so that's the best match.
You could try replacing the ToJsonClass() in JsonParameterStreamRef with something like this:
public override Parameter ToJsonClass(StStParameter arg, Parameter source = null)
{
if (arg.GetType() == typeof (StStParameterEventStreamRef))
{
return ToJsonClass(arg as StStParameterEventStreamRef, source as ParameterEventStreamRef);
}
return base.ToJsonClass(arg, source); // or throw an exception if this is an error.
}
The following is a working solution to the problem, but if you can come up with a better solution, please.
public Parameter GetConverterFactory_AndDo_ToJsonClass(StStParameter stStParameter)
{
if (stStParameter.GetType() == typeof (StStParameterEventStreamRef))
return new JsonParameterEventStreamRefConverter().ToJsonClass(stStParameter as StStParameterEventStreamRef);
throw new InvalidEnumArgumentException(stStParameter.GetType().FullName);
}
I would expect Enumerable.Empty<string>() to return an empty array of strings. Instead, it appears to return an array with a single null value. This breaks other LINQ operators like DefaultIfEmpty, since the enumerable is not, in fact, empty. This doesn't seem to be documented anywhere, so I'm wondering if I'm missing something (99% probability).
GameObject Class
public GameObject(string id,IEnumerable<string> keywords) {
if (String.IsNullOrWhiteSpace(id)) {
throw new ArgumentException("invalid", "id");
}
if (keywords==null) {
throw new ArgumentException("invalid", "keywords");
}
if (keywords.DefaultIfEmpty() == null) { //This line doesn't work correctly.
throw new ArgumentException("invalid", "keywords");
}
if (keywords.Any(kw => String.IsNullOrWhiteSpace(kw))) {
throw new ArgumentException("invalid", "keywords");
}
_id = id;
_keywords = new HashSet<string>(keywords);
}
Test
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void EmptyKeywords() {
GameObject test = new GameObject("test",System.Linq.Enumerable.Empty<string>());
}
It looks like you expect this condition:
keywords.DefaultIfEmpty() == null
to evaluate to true. However DefaultIfEmpty returns a singleton sequence containing the default for the element type (string in this case) if the source sequence is empty. Therefore it will return a sequence containing null. This is not itself null however so the condition returns false.
You are misinterpreting the implementation of DefaultIfEmpty, here is it's implementation from the reference source.
public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source) {
return DefaultIfEmpty(source, default(TSource));
}
public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source, TSource defaultValue) {
if (source == null) throw Error.ArgumentNull("source");
return DefaultIfEmptyIterator<TSource>(source, defaultValue);
}
static IEnumerable<TSource> DefaultIfEmptyIterator<TSource>(IEnumerable<TSource> source, TSource defaultValue) {
using (IEnumerator<TSource> e = source.GetEnumerator()) {
if (e.MoveNext()) {
do {
yield return e.Current;
} while (e.MoveNext());
}
else {
yield return defaultValue;
}
}
}
So what it does is if a IEnumerable<T> is not empty it simply returns the IEnumerable<T>, if the IEnumerable<T> is empty it returns new a IEnumerable<T> with one object in it with the value default(T). It will never return null which is what your test is testing for. If you wanted to test this you would need to do
if(keywords.DefaultIfEmpty().First() == null)
However this is going to cause the IEnumerable<string> to be evaluated multiple times. I would drop the LINQ and just do like the LINQ method does and do it the long way (this also gets rid of the extra evaluation you had inside new HashSet<string>(keywords)).
public GameObject(string id,IEnumerable<string> keywords)
{
if (String.IsNullOrWhiteSpace(id)) {
throw new ArgumentException("invalid", "id");
}
if (keywords==null) {
throw new ArgumentException("invalid", "keywords");
}
_keywords = new HashSet<string>();
using (var enumerator = keywords.GetEnumerator())
{
if (e.MoveNext())
{
do
{
if(e.Current == null)
throw new ArgumentException("invalid", "keywords");
_keywords.Add(e.Current);
} while (e.MoveNext());
}
else
{
throw new ArgumentException("invalid", "keywords");
}
}
_id = id;
}
This makes it so you only loop once over the IEnumerable<string>.
Does this solve your problem?
public GameObject(string id, IEnumerable<string> keywords) {
if (String.IsNullOrWhiteSpace(id)) {
throw new ArgumentException("invalid", "id");
}
if (keywords == null || !keywords.Any()
|| keywords.Any(k => String.IsNullOrWhiteSpace(k))) {
throw new ArgumentException("invalid", "keywords");
}
_id = id;
_keywords = new HashSet<string>(keywords);
}
*Improved the code with suggestions from #ScottChamberlain & #ginkner
In a controller I can perform DB lookups etc and add some error message associated with a model property:
public ActionResult CreateJob(CreateJobModel viewModel)
{
var call = FindCall(viewModel.CallNumber);
if (call == null)
{
ModelState.AddModelError("CallNumber", "Idiot User!");
}
}
I don't like that CallNumber is a string, when ideally it should refer directly to viewModel.CallNumber, and if I change the name of that property, it should be changed too.
How can I achieve this?
I'd imagine the code would end up something like this, which would take a property access expression:
AddModelFieldError(() => viewModel.CallNumber, "Idiot User!");
But I'm not sure how to create a method like that, or in the case where it's a sub/inner-property that needs the error message.
I would write my own generic extension method:
public static class ModelStateDictionaryHelper
{
public static void AddModelError<TViewModel>(
this ModelStateDictionary me,
Expression<Func<TViewModel, object>> lambdaExpression, string error)
{
me.AddModelError(GetPropertyName(lambdaExpression), error);
}
private static string GetPropertyName(Expression lambdaExpression)
{
IList<string> list = new List<string>();
var e = lambdaExpression;
while (true)
{
switch (e.NodeType)
{
case ExpressionType.Lambda:
e = ((LambdaExpression)e).Body;
break;
case ExpressionType.MemberAccess:
var propertyInfo = ((MemberExpression)e).Member as PropertyInfo;
var prop = propertyInfo != null
? propertyInfo.Name
: null;
list.Add(prop);
var memberExpression = (MemberExpression)e;
if (memberExpression.Expression.NodeType != ExpressionType.Parameter)
{
var parameter = GetParameterExpression(memberExpression.Expression);
if (parameter != null)
{
e = Expression.Lambda(memberExpression.Expression, parameter);
break;
}
}
return string.Join(".", list.Reverse());
default:
return null;
}
}
}
private static ParameterExpression GetParameterExpression(Expression expression)
{
while (expression.NodeType == ExpressionType.MemberAccess)
{
expression = ((MemberExpression)expression).Expression;
}
return expression.NodeType == ExpressionType.Parameter ? (ParameterExpression)expression : null;
}
}
and the usage:
ModelState.AddModelError<CreateJobModel>(x => x.CallNumber,
"some kind attention");
It looks a bit differently from the version you've asked about, but I hope it can be acceptable alternative.
As of C# 6, you can use the nameof operator.
public ActionResult CreateJob(CreateJobModel viewModel)
{
var call = FindCall(viewModel.CallNumber);
if (call == null)
{
ModelState.AddModelError(nameof(CreateJobModel.CallNumber), "Idiot User!");
}
}
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;
}