How to handle ProblemDetails response from API in .NET MAUI app [duplicate] - c#

I've looked through many questions that are similar to this, but none of them really touched on what I precisely want to do. What I am trying to do is read from an external source a list of variables that also include their data type into a string array:
Example:
ID/Key Type Value/Data;
varName1 bool true;
varName2 string str;
varName3 int 5;
I then store these are objects into a dictionary as objects containing several strings, with the ID also serving as the key.
What I want to do is now create a method that uses a switch statement that casts the string into the correct datatype, and returns it without having to specify anything in the method call. The function should look something like this:
public ??? Method(string key)
{
if(dictionary.ContainsKey(ID))
{
Var temp = dictionary[ID];
switch (temp.Type)
{
case "bool":
return Convert.ToBoolean(temp.Value);
case "int"
return Convert.ToInt(temp.Value);
case "string"
return temp.Value;
}
}
return "NULL";
}
The method call should look something like this:
int x = Method(string key);
string word = Method(string key);
bool isTrue = Method(string key);
Maybe I've missed something, but I have yet to find something that really does something quite like this. Any and all thoughts about this are welcome as well.

In C# 7 you have the option to return multiple values from a method like this:
public (string SomeString, int SomeInt) DoSomething() { ... }
You can get the values like this:
var result = DoSomething();
Console.WriteLine(result.SomeString);
Console.WriteLine(result.SomeInt.ToString());
Or
(var someString, var someInt) = DoSomething();
Console.WriteLine(someString);
Console.WriteLine(someInt.ToString());
This works below the surface with a Tuple and you are not restricted to only 2 values. I don't know how many you can return but I suggest when you need to return that many values, create a class.
More info: https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/

Update
I believe a lot of people are arriving at this question because they're looking for ways to return multiple values generally, not necessarily for the purposes given in the original question. If this is what you want, there are a few options to choose from.
If the combination of your returned types represents a concept that may be useful outside of your method call, consider creating a type to represent that concept. C#'s records provide a nice, concise way to do that:
public record ExtractedValue(bool? BooleanValue, string? StringValue, int? IntValue);
public ExtractedValue Method(string key)
{
...
}
If this is the only place these values will appear together, and it's not really worth coming up with a named type to represent the values, you can also use a Value Tuple. Just be aware that there are some behavioral implications that might bite you if you plan to use the type for things like serialization.
public (bool? BooleanValue, string? StringValue, int? IntValue) Method(string key)
{
...
}
Original Answer
The compiler has no way to distinguish between the three method calls you've provided, because they all look like Method(key);
One option is to return an object and then expect the consuming code to cast it to what they want:
public object Method(string key)
{
if(dictionary.ContainsKey(key))
{
var temp = dictionary[key];
switch (temp.Type)
{
case "bool":
return Convert.ToBoolean(temp.Value);
case "int"
return Convert.ToInt(temp.Value);
case "string"
return temp.Value;
}
}
return "NULL";
}
...
int x = (int) Method(key);
string word = (string) Method(key);
bool isTrue = (bool) Method(key);
You could also use the dynamic keyword to make the cast implicit:
public dynamic Method(string key)
{
if(dictionary.ContainsKey(key))
{
var temp = dictionary[key];
switch (temp.Type)
{
case "bool":
return Convert.ToBoolean(temp.Value);
case "int"
return Convert.ToInt(temp.Value);
case "string"
return temp.Value;
}
}
return "NULL";
}
...
int x = Method(key);
string word = Method(key);
bool isTrue = Method(key);
However, dynamic is a very powerful concept, and it's easy for it to get out of hand, so you have to be really careful with that.
It seems to me that you're expecting your calling code to know which type of object it's expecting to get for each key. It seems like maybe the best approach is to just let the user supply that information:
public T Method<T>(string key)
{
if(dictionary.ContainsKey(key))
return (T) Convert.ChangeType(dictionary[key].Value, typeof(T));
return default(T);
}
...
int x = Method<int>(key);
string word = Method<string>(key);
bool isTrue = Method<bool>(key);
That way, there's no need to track the Type value in your dictionary objects in the first place.

The return type of a function must be typed. As with any other variable or operation, any type that inherits from the specified type is a valid return value (which is why object allows anything as a value).
Personally i dont think it is useful to make one method with multiple return types but if you really want to have one method with multiple return types, you could use the dynamic type in .NET 4.0:
private static void Main(string[] args)
{
int x = Method("varName3");
string word = Method("varName2");
bool isTrue = Method("varName1");
}
private static dynamic Method(string key)
{
var dictionary = new Dictionary<string, KeyValuePair<Type, object>>()
{
{ "varName1", new KeyValuePair<Type, object>(typeof(bool), false) },
{ "varName2", new KeyValuePair<Type, object>(typeof(string), "str") },
{ "varName3", new KeyValuePair<Type, object>(typeof(int), 5) },
};
if (dictionary.ContainsKey(key))
{
return dictionary[key].Value;
}
return null;
}
Hope it helps

Related

Dynamic if condition

Tried searching online for this but no luck so far
Basically I allow the user create an expression of choices such as
TargetHealthLessThen20
TargetAboutToUsePotion
These are stored against an enum and then stored in database as a string expression such as
"TargetHealthLessThen20 || TargetAboutToUsePotion"
now I have methods for each enum to check its conditon i.e
public bool IsTargetHealthLessThen20(Target target)
{
// do login
}
public bool IsTargetAboutToUsePotion(Target target)
{
// do login
}
I want to be able to write an If statement that was dynamic to call these methods and put in the conditons such as
if("IsTargetHealthLessThen20(target) || IsTargetAboutToUsePotion(target)")
{
// Perform Action
}
Any ideas on best way of going about this?
While I wouldn't necessarily recommend the following due to performance reasons, it will do what you want.
If you are always applying your target and only your target, you can predefine a class of evaluative methods and then pass in a list of string method names to evaluate against those methods.
void Main()
{
var inputs = new List<string>();
inputs.Add("MethodA");
inputs.Add("MethodB");
var results = Evaluate(inputs, "target");
Console.WriteLine(results);
}
public bool Evaluate(List<string> predicates, string target)
{
var methods = new Methods();
var tempResult = false;
foreach (var pred in predicates)
{
var method = methods.GetType().GetMethod(pred);
if (method == null)
throw new InvalidOperationException(
string.Format("Unknown method {0}.", pred));
tempResult = (bool)typeof(Methods).GetMethod(pred).Invoke(methods, new [] {target});
if (!tempResult) break;
continue;
}
return tempResult;
}
public class Methods
{
public bool MethodA(string target)
{
return target == "target";
}
public bool MethodB(string target)
{
return target == "not a target";
}
}
This particular Evaluate function will evaluate AND conditions. You would need to change your evaluative logic for OR conditions. You could in theory inspect your strings and call a different method depending on the operators in the strings.
EDIT
A second option that would avoid reflection would be to create a Dictionary that maps your string names for your methods to the methods themselves. This would allow you to achieve the same result without reflection, although you would have to keep your dictionary in sync. On the flip side, you gain and additional compile-time check without the reflection overhead.
private static readonly Methods _methodsInstance = new Methods();
private static Dictionary<string, Func<string, bool>> _methods = new Dictionary<string, Func<string, bool>>()
{
{ "MethodA", _methodsInstance.MethodA },
{ "MethodB", _methodsInstance.MethodB },
};
public bool Evaluate(List<string> predicates, string target)
{
var tempResult = false;
foreach (var pred in predicates)
{
tempResult = _methods[pred](target);
if (!tempResult) break;
continue;
}
return tempResult;
}
I think it's diffcult. Because you don't know the target parameter value. if you know the parameter value, you can use the reflect invoke the method by expression string.
I think I have just the answer you're looking for, because I needed the nearly exact same thing in the past:
What you have there is C# code, so you need to treat it like what it is :)
Create an interface like
interface ICondition { bool Evaluate(); }
Now use the text you have there to compile it into a class.
Like this:
using YourProgramNamespace;
class myCondition : ICondition
{
bool Evaluate() { return {0} ; }
}
To pass more parameters just change the interface to allow for the matching parameters.
If you don't want multiple interfaces just make it like this:
using YourProgramNamespace;
class myCondition : ICondition
{
bool Evaluate(params object[] parameters) { return {0} ; }
}
In your text you then just write it like this:
TargetHasLessThan20Hp((TargetType)parameters[0])
Where you replace the {0} with the condition text you already have.
Use the C# compiler to compile the code.
http://msdn.microsoft.com/de-de/library/microsoft.csharp.csharpcodeprovider%28v=vs.110%29.aspx
There are more than enough tutorials on how to use it and it's usage is not that hard.
When you have compiled the class into a Dll load it and find the type with reflection, this is also not hard and there are tons of tutorials out there. Just use yourAssembly.GetTypes() and go from there
Use Activator.CreateInstance to instantiate the type you have
Then just call the evaluate function and it will return true or false.
For better performance don't compile each time until the condition text actually changes.
Need more info? Just ask and I'll edit my answer or post it in the comments.

Are mutiple methods recommended when returning different types?

I'm returning values from an Entity object. Some of them are String typed and some are not. Right now, I did a quick solution as follows.
private String GetStringValue(Entity entity, String attribute, String substitute = "")
{
if(entity.Contains(attribute)
return entity[attribute] as String;
return substitute;
}
private String GetIntValue(Entity entity, String attribute, int substitute = 0)
{
if(entity.Contains(attribute)
return entity[attribute] as int;
return substitute;
}
Then I remembered that there's a syntax for generic typing (something like <TypeX>). My question is, however, if there's a point to start changing the existing code. I'll need to change the signature of the method in two places (return type and substitute type) but I fear that I'll need to do some complex coding inside the method as well.
On the other hand, I'd have a nice way to treat all the types possible (and I have a hunch we'll be working with more than strings and integers.
You will have to change the signature of the method in three places, because you also have to add the generic parameter:
private T GetValue<T>(Entity entity, String attribute, T substitute)
Within the method, there's no real need for any complex coding; replacing your current occurrences of string or int, respectively, with T, should suffice. (Note that the as operator can only be applied if you restrict T to reference types - which you probably don't want to do, because int is a value type).
Note that there are two issues with this method that you might consider drawbacks:
This generic method will support "all the types possible", but it will also support any types impossible (users are free to specify whatever type they like for T, and there is no way to restrict T while still supporting both string and int.
You cannot specify arbitrary default substitute values for each type. What you can do is declare a default value for substitute, namely default(T), but at least for string, that is not an empty string, but null.
You are right "something like" is the generic method. Check out generic methods there.
Next method looks good for your purpose.
private static T GetValue<T>(Entity entity, string attribute, T defaultValue)
{
if (!entity.Contains(attribute))
return defaultValue;
return (T)entity[attribute];
}
EDIT: updated according of the w0lf's comment.
If you don't want to change method signature, you can write a generic function and call it from all of these non generic versions.
private String GetStringValue(...){
return GetValue<String>(...);
}
By the way, you are looking for Generic methods
For e.g (from msdn)
static void Swap<T>(ref T lhs, ref T rhs)
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
...
Swap<int>(ref a, ref b);
or just
Swap(ref a, ref b); //type int is infered based on type of arguements and method signature
What class is Entity? Assuming it's a custom class, make it also generic, then this works:
private T Get<T>(Entity<T> entity, T attribute, T substitute = default(T))
{
if (entity.Contains(attribute))
return entity[attribute];
return substitute;
}
You can retrieve the value in this way:
var entity = new Entity<string>();
string val = Get<string>(entity, "attr", "subst");
You should define your Entity<T> class:
public class Entity<T>
{
// TODO: implement
public T this[string i] { get; set; }
// TODO: implement
internal bool Contains(string attribute)
{
return true;
}
// TODO: implement
// other properties and methods
}
And you may use a generic method:
private T GetStringValue<T>(Entity<T> entity, String attribute, T substitute = default(T))
{
if (entity.Contains(attribute))
return entity[attribute];
return substitute;
}
If it is possible to generalize the code inside a method I would absolutely recommend to use it in a generic way. It makes the class smaller, better readable and you just have to change one method if requirements change. Your method looks like it can be made generic easily.
private T GetIntValue<T>(Entity entity, String attribute, T substitute = default(T))
{
if(entity.Contains(attribute))
return (T)entity[attribute];
return substitute;
}
If there would be some more logic to execute you could also use a dictionary with functions for the different types:
private IDictionary<Type, Func<Entity, string, object>> actions;
private void InitActions()
{
actions = new Dictionary<Type, Func<Entity, string, object>>
{
{
typeof (string), (entity, attribute) =>
{
// this could be your custom code for string
return entity[attribute];
}
},
{
typeof (int), (entity, attribute) =>
{
// this could be your custom code for int
return entity[attribute];
}
}
};
}
private T GetIntValue<T>(Entity entity, String attribute, T substitute = default(T))
{
if (entity.Contains(attribute) && actions.ContainsKey(typeof (T)))
{
Func<Entity, string, object> action = actions[typeof (T)];
return (T)action(entity, attribute);
}
return substitute;
}

How to make method to return generic type?

I have a class named config with one string field named key.
When I apply the GET property of the class, the property has to return one variable key in different types (Int or bool or String).
I implemented it as follow:
public enum RetType {RetInt, RetBool, RetString};
...
public object PolimorphProperty(string key, RetType how)
{
get
{
switch (how)
{
case RetType.RetInt:
...;
case RetType.RetBool:
...;
case RetType.RetString:
...;
}
}
}
But the problem that PolimorphProperty returns Object type.
What should I change in the code to get the appropriate type (int,bool,string), not the object?
Do this:
public T PolimorphProperty<T>(string key)
{
return (T) objectInstanceHere;
}
Usage example:
int i = PolimorphProperty<int>("somekey");
And this supports the http://www.antiifcampaign.com/
As much as possible avoid switch, if for that matter, in a polymorphic code.
public T PolimorphProperty<T>(string key, T how)
{
//todo
}
Any type in C# is actually an object.
From what I understood from your question, you call your method this way:
PolimorpthProperty(key, RetType.SomeType)
The method returns an object. You should use it this way:
int key = (int)PolimorthProperty(key, RetType.RetInt);
This is called Unboxing.
How about this, consider that you original implementation of 'PolimorphProperty' remains im your project and you add this:
public TType PolimorphProperty<TType>(string key, RetType how)
{
return (TType)PolimorphProperty(key, how);
}
If I understood correctly, you are looking for something like this:
public T GenericMethod<T>(string key)
{
var ret = new object(); // Retrieve object from whatever...
return (T) ret;
}
public void UsageExample()
{
int typedResult = GenericMethod<int>("myKey");
}
If you are trying to fetch different objects based on the type T, with different logic, than you'll have to switch on types anyway, Because unless your collection supports objects of certain type (they usually do), the compiler doesn't know what to do.
In this case, check this question.

C# Generics and Type Checking

I have a method that uses an IList<T> as a parameter. I need to check what the type of that T object is and do something based on it. I was trying to use the T value, but the compiler does not not allow it. My solution is the following:
private static string BuildClause<T>(IList<T> clause)
{
if (clause.Count > 0)
{
if (clause[0] is int || clause[0] is decimal)
{
//do something
}
else if (clause[0] is String)
{
//do something else
}
else if (...) //etc for all the types
else
{
throw new ApplicationException("Invalid type");
}
}
}
There has to be a better way to do this. Is there some way I can check the type of T that is passed in and then use a switch statement?
You could use overloads:
public static string BuildClause(List<string> l){...}
public static string BuildClause(List<int> l){...}
public static string BuildClause<T>(List<T> l){...}
Or you could inspect the type of the generic parameter:
Type listType = typeof(T);
if(listType == typeof(int)){...}
You can use typeof(T).
private static string BuildClause<T>(IList<T> clause)
{
Type itemType = typeof(T);
if(itemType == typeof(int) || itemType == typeof(decimal))
...
}
And, because C# has evolved, you can (now) use pattern matching.
private static string BuildClause<T>(IList<T> clause)
{
if (clause.Count > 0)
{
switch (clause[0])
{
case int x: // do something with x, which is an int here...
case decimal x: // do something with x, which is a decimal here...
case string x: // do something with x, which is a string here...
...
default: throw new Exception("Invalid type");
}
}
}
And again with switch expressions in C# 8.0, the syntax gets even more succinct.
private static string BuildClause<T>(IList<T> clause)
{
if (clause.Count > 0)
{
return clause[0] switch
{
int x => "some string related to this int",
decimal x => "some string related to this decimal",
string x => x,
...,
_ => throw new Exception("Invalid type")
}
}
}
I hope you find this helpful:
typeof(IList<T>).IsGenericType == true
typeof(IList<T>).GetGenericTypeDefinition() == typeof(IList<>)
typeof(IList<int>).GetGenericArguments()[0] == typeof(int)
https://dotnetfiddle.net/5qUZnt
By default know there is not a great way. Awhile back I got frustrated with this and wrote a little utility class that helped out a bit and made the syntax a bit cleaner. Essentially it turns the code into
TypeSwitcher.Do(clause[0],
TypeSwitch.Case<int>(x => ...), // x is an int
TypeSwitch.Case<decimal>(d => ...), // d is a decimal
TypeSwitch.Case<string>(s => ...)); // s is a string
Full blog post and details on the implementation are available here
http://blogs.msdn.com/jaredpar/archive/2008/05/16/switching-on-types.aspx
The typeof operator...
typeof(T)
... won't work with the c# switch statement. But how about this? The following post contains a static class...
Is there a better alternative than this to 'switch on type'?
...that will let you write code like this:
TypeSwitch.Do(
sender,
TypeSwitch.Case<Button>(() => textBox1.Text = "Hit a Button"),
TypeSwitch.Case<CheckBox>(x => textBox1.Text = "Checkbox is " + x.Checked),
TypeSwitch.Default(() => textBox1.Text = "Not sure what is hovered over"));
There is no way to use the switch statement for what you want it to do. The switch statement must be supplied with integral types, which does not include complex types such as a "Type" object, or any other object type for that matter.
For everyone that says checking types and doing something based on the type is not a great idea for generics I sort of agree but I think there could be some circumstances where this perfectly makes sense.
For example if you have a class that say is implemented like so (Note: I am not showing everything that this code does for simplicity and have simply cut and pasted into here so it may not build or work as intended like the entire code does but it gets the point across. Also, Unit is an enum):
public class FoodCount<TValue> : BaseFoodCount
{
public TValue Value { get; set; }
public override string ToString()
{
if (Value is decimal)
{
// Code not cleaned up yet
// Some code and values defined in base class
mstrValue = Value.ToString();
decimal mdecValue;
decimal.TryParse(mstrValue, out mdecValue);
mstrValue = decimal.Round(mdecValue).ToString();
mstrValue = mstrValue + mstrUnitOfMeasurement;
return mstrValue;
}
else
{
// Simply return a string
string str = Value.ToString() + mstrUnitOfMeasurement;
return str;
}
}
}
...
public class SaturatedFat : FoodCountWithDailyValue<decimal>
{
public SaturatedFat()
{
mUnit = Unit.g;
}
}
public class Fiber : FoodCount<int>
{
public Fiber()
{
mUnit = Unit.g;
}
}
public void DoSomething()
{
nutritionFields.SaturatedFat oSatFat = new nutritionFields.SaturatedFat();
string mstrValueToDisplayPreFormatted= oSatFat.ToString();
}
So in summary, I think there are valid reasons why you might want to check to see what type the generic is, in order to do something special.
Your construction completely defeats the purpose of a generic method. It's ugly on purpose because there must be a better way to achieve what you're trying to accomplish, although you haven't given us quite enough information to figure out what that is.
You can do typeOf(T), but I would double check your method and make sure your not violating single responsability here. This would be a code smell, and that's not to say it shouldn't be done but that you should be cautious.
The point of generics is being able to build type-agnostic algorthims were you don't care what the type is or as long as it fits within a certain set of criteria. Your implementation isn't very generic.
How about this :
// Checks to see if the value passed is valid.
if (!TypeDescriptor.GetConverter(typeof(T)).IsValid(value))
{
throw new ArgumentException();
}
My two cents:
In case you happen to have a generic method that returns a generic value but doesn't have generic parameters, you can use default(T) + (T)(object) cast, together with C# 8 pattern matching/type checks (as indicated in the other recent answers).
Example:
private static T Parse<T>(string str)
{
return default(T) switch
{
short => (T)(object)short.Parse(str),
ushort => (T)(object)ushort.Parse(str),
int => (T)(object)int.Parse(str),
uint => (T)(object)uint.Parse(str),
long => (T)(object)long.Parse(str),
ulong => (T)(object)ulong.Parse(str),
_ => throw new ArgumentException()
};
}

C# - method behaviour that depends on the expected type

Is it possible to write in C# method in such a way that when I write
String contestId = getParameter("contestId")
i get contestId in string, but when I write:
int contestId = getParameter("contestId")
i get contestId parsed to integer?
This is only simple example showing what i try to achieve.
Nope it's not possible to overload methods solely based on their return type. You could, however, introduce a generic parameter:
T getParameter<T>(string input) {
// ... do stuff based on T ...
}
And if you were using C# 3.0 you could use this method as:
var str = getParameter<string>("contestid");
var integer = getParameter<int>("contestid");
thus saying the actual type only once.
One thing you could do is return a separate object, which has implicit conversion operators to both int and string. That would get fairly close to the behavior you're asking for.
I wouldn't do that in practice though. Implicit conversions generally cause more trouble than they're worth.
Instead, add a generic parameter, like Mehrdad showed:
var str = getParameter<string>("contestid");
var integer = getParameter<int>("contestid");
I prefer this approach, it reads nicely.
Public Class ResultProxy
{
Private Object _Obj
Public ResultProxy(Object O)
{ _Obj = O; }
Public T As<T>()
{ return (T)_Obj; }
}
...
Public ResultProxy getParameter("contestId")
{
// your method's code
return new ResultProxy(YourPersonalFavorateReturnType);
}
...
String s = getParameter("contestId").As<String>();
Firstly the answer is no as many people have mentioned. Why? Do you have to assign the result of a method to something? For example can you have
int getValue()
{
return 4;
}
getValue();
The answer is yes, it can, so there is no way for the compiler to know which method you intend to call by its return type.
Personal opinion here, but I would suggest something along the lines of
public string getContestIdAsString(string ConetestId);
public int getContestIdAsInt(string ContestId);
Very obvious what each one is doing and you get around your problem. Unless there is something that I am missing.
public T GetParameter<T>(string parameterName)
{
//Do work
return value
}
string contestId = getParameter<string>("contestId")
int contestId = getParameter<int>("contestId")
This is an example of your best bet.

Categories