Dynamic if condition - c#

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.

Related

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

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

Roslyn: How to get the ITypeSymbol associated with an identifier?

I'm attempting to write a Roslyn analyzer to detect usages of Enumerable.Count() being called on arrays. Here is the relevant code in my analyzer:
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeInvocationExpression, SyntaxKind.InvocationExpression);
}
private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context)
{
var invocation = (InvocationExpressionSyntax)context.Node;
var memberAccess = invocation.Expression as MemberAccessExpressionSyntax;
if (!memberAccess.IsKind(SyntaxKind.SimpleMemberAccessExpression))
{
return;
}
Debug.Assert(memberAccess != null);
var ident = memberAccess.Name.Identifier;
// Check whether the method is Count() and there is no parameter list before we try to use the Symbol APIs.
if (ident.ToString() != nameof(Enumerable.Count))
{
return;
}
var arguments = invocation.ArgumentList.Arguments;
if (arguments.Count > 0)
{
return;
}
// Make sure that the subject is an array.
var subject = memberAccess.Expression;
var subjectSymbol = context.SemanticModel.GetSymbolInfo(subject).Symbol;
if (subjectSymbol == null)
{
return;
}
// ???
}
I'm stuck trying to determine whether the object that Count() is being invoked on is an array. I scanned the API a bit and I see there is an ILocalSymbol with a Type property, and also an IFieldSymbol with a Type property that will both presumably get you the type of the object. However, I don't know whether the object I'm analyzing is a local/field/result of a method call/etc, so I would expect IFieldSymbol and ILocalSymbol to e.g. share some common base interface, say IVariableSymbol, that offers you the Type without having to know all the possible places the variable could have come from. However, it seems both interfaces derive directly from ISymbol.
Is the best solution just to do something like this?
internal static class SymbolUtilities
{
public static ITypeSymbol GetType(ISymbol symbol)
{
if (symbol is IFieldSymbol)
{
return ((IFieldSymbol)symbol).Type;
}
if (symbol is ILocalSymbol)
{
return ((ILocalSymbol)symbol).Type;
}
...
}
}
You can get the information about the type, using the method GetTypeInfo of the SemanticModel class:
ITypeSymbol subjectType = context.SemanticModel.GetTypeInfo(subject).Type;
You will find more details about it in the article
"Introduction to Roslyn and its use in program development"

The repository pattern and LinqToSql methods

I have an object that encapsulates a linq to sql data context.
It has a method IQuerable<T> FromStore<T> that allows me to get my entities from the appropriate table via linq to sql.
I also have call-through methods to call functions on the data context.
The problem I have now is that I can't use those pass through methods within where clauses because there's no translation to sql. I understand why this is happening, but how can I work around it?
Example code:
In my repository class:
public class AquaReportsRepository : LinqToSqlRepository<int>, IAquaReportsRepository
{
public bool IsPhysicalItem(string itemNumber)
{
return _UnderlyingDataContext.Aqua_IsPhysicalItem(itemNumber) ?? true;
}
}
Trying to access data from it:
from part in Repository.FromStore<Parts>()
where !(Repository.IsPhysicalItem(part.Item)) // eek, not translation to sql
select part.ItemNumber;
In the past, where I've needed a simple property on a data object, calculated from another property i've used QueryMap to translate the property into an equivalent expression, however I don't think I can do that here as I need to access a datacontext method.
TL;DR: Read the example for point 1. Use the code in QueryMap, making the changes in bold below.
Right, I've managed to work around this using some slight modifications to QueryMap
There were 2 things I needed to get working:
Figure out how to tell querymap to call a method that uses the data context?
Figure out how to get querymap to pick up the attribute defined on a class, when being accessed via an interface.
The first part was fairly simple:
private static readonly ExpressionMethod<Func<AquaReportsRepository, string, bool>> _IsPhysicalItem =
ExpressionMethod.Create((AquaReportsRepository ardc, string i) => ardc._AquaReportsDC.Aqua_IsPhysicalItem(i) ?? true);
[MapToExpression("_IsPhysicalItem")]
public bool IsPhysicalItem(string itemNumber)
{
return _IsPhysicalItem.Invoke(this, itemNumber);
}
The key here is to simply use a function that takes the object itself as the first argument (AquaReportsRepository in this case) in addition to the normal other argument(s).
The second part however required some (fairly minor) changes to MappedQueryVisitor.cs. in both cases only a single if statement (with statements inside!).
Replace the existing GetLambda method with this:
private LambdaExpression GetLambda(Expression receiver, MemberInfo member) {
LambdaExpression exp;
if(!_mappings.TryGetValue(member, out exp)) {
exp = _mappingLookup(member);
if(null == exp) {
var attr = (MapToExpressionAttribute) member.GetCustomAttributes(typeof(MapToExpressionAttribute), true).FirstOrDefault();
// Added by me to deal with interfaces
if (null == attr)
{
if (null != receiver)
{
// member could be an interface's member, so check the receiver.object type
if (receiver.NodeType == ExpressionType.Constant)
{
var receiverType = ((ConstantExpression)receiver).Value.GetType();
var receiverMemberInfo = receiverType.GetMembers().Where(mi => mi.Name == member.Name).SingleOrDefault();
if (null != receiverMemberInfo)
{
attr = (MapToExpressionAttribute)receiverMemberInfo.GetCustomAttributes(typeof(MapToExpressionAttribute), true).FirstOrDefault();
member = receiverMemberInfo;
}
}
}
}
if(null != attr) {
exp = GetLambdaFromAttribute(receiver, member.DeclaringType, attr);
}
}
_mappings.Add(member, exp);
}
return exp;
}
This change means that if we have a member MethodInfo object representing an interfaces method we will recognise that and try and get the actual MethodInfo of the concrete type we're working with (defined by the constant expression).
Now it correctly picks up the MapToExpressionAttribute attribute on the implementing class, given the MemberInfo of an interface.
The next issue though is with VisitMethodCall, where having got the replacement expression to invoke from the attribute it fails because the argument expression is the interface type, by the method we're invoking requires the implementing class.
This last code change corrects that.
Change the CollectArguments method to this:
private static IEnumerable<Expression> CollectArguments(MethodCallExpression m) {
IEnumerable<Expression> args = m.Arguments;
if (!m.Method.IsStatic)
{
var objectExpression = m.Object;
// Added by me, to deal with interfaces
if (objectExpression.NodeType == ExpressionType.Constant)
{
var objectConstExpression = ((ConstantExpression)objectExpression);
if (objectConstExpression.Type.IsInterface)
{
objectExpression = Expression.Constant(objectConstExpression.Value);
}
}
args = Enumerable.Repeat(objectExpression, 1).Concat(args);
}
return args;
}

Better Alternative to Case Statement

I currently have a switch statement that runs around 300 odd lines. I know this is not as giant as it can get, but I'm sure there's a better way to handle this.
The switch statement takes an Enum that is used to determine certain properties that pertain to logging. Right now the problem sets in that it is very easy to leave out an enumeration value and that it will not be given a value as it is not in the switch statement.
Is there an option one can use to ensure that every enumeration is used and given a custom set of values it needs to do its job?
EDIT:
Code sample as requested: (This is simplistic, but shows exactly what I mean. Also an Enumeration would exist with the below values.)
internal void GenerateStatusLog(LogAction ActionToLog)
{
switch (ActionToLog)
{
case LogAction.None:
{
return;
}
case LogAction.LogThis:
{
ActionText = "Logging this Information";
LogText = "Go for it.";
break;
}
}
// .. Do everything else
}
EDIT
I thought this over again, looked around in related questions in SO, and I wrote some code. I created a class named AdvancedSwitch<T>, which allows you to add cases and exposes a method to evaluate a value and lets you specify values that it should check for existence.
This is what I came up with:
public class AdvancedSwitch<T> where T : struct
{
protected Dictionary<T, Action> handlers = new Dictionary<T, Action>();
public void AddHandler(T caseValue, Action action)
{
handlers.Add(caseValue, action);
}
public void RemoveHandler(T caseValue)
{
handlers.Remove(caseValue);
}
public void ExecuteHandler(T actualValue)
{
ExecuteHandler(actualValue, Enumerable.Empty<T>());
}
public void ExecuteHandler(T actualValue, IEnumerable<T> ensureExistence)
{
foreach (var val in ensureExistence)
if (!handlers.ContainsKey(val))
throw new InvalidOperationException("The case " + val.ToString() + " is not handled.");
handlers[actualValue]();
}
}
You can consume the class this way:
public enum TrafficColor { Red, Yellow, Green }
public static void Main()
{
Console.WriteLine("Choose a traffic color: red, yellow, green?");
var color = (TrafficColor)Enum.Parse(typeof(TrafficColor), Console.ReadLine());
var result = string.Empty;
// Creating the "switch"
var mySwitch = new AdvancedSwitch<TrafficColor>();
// Adding a single case
mySwitch.AddHandler(TrafficColor.Green, delegate
{
result = "You may pass.";
});
// Adding multiple cases with the same action
Action redAndYellowDelegate = delegate
{
result = "You may not pass.";
};
mySwitch.AddHandler(TrafficColor.Red, redAndYellowDelegate);
mySwitch.AddHandler(TrafficColor.Yellow, redAndYellowDelegate);
// Evaluating it
mySwitch.ExecuteHandler(color, (TrafficColor[])Enum.GetValues(typeof(TrafficColor)));
Console.WriteLine(result);
}
With the creative use of anonymous delegates, you can easily add new cases to your "switch block". :)
Not that you can also use lambda expressions, and lambda blocks, eg () => { ... } instead of delegate { ... }.
You can easily use this class instead of the long switch blocks.
Original post:
If you use Visual Studio, always create swich statements with the switch code snippet. Type switch press tab twice, and it auto-generates all the possibilities for you.
Then, add a default case to the end which throws an exception, that way when testing your app you will notice that there is an unhandled case, instantly.
I mean something like this:
switch (something)
{
...
case YourEnum.SomeValue:
...
break;
default:
throw new InvalidOperationException("Default case reached.");
}
Well, there's throwing in the default case... There's no edit / compile time construct other than that.
However Strategy, Visitor and other patterns related to them may be appropriate if you choose to do it at run time.
Sample code will help with getting the best answer.
EDIT: Thanks for the sample. I still think it needs a bit of fleshing out as you dont cover whether there are some parameters that only apply to some cases etc.
Action is often used as an alias for the Command pattern and the fact that your Enum is called LogAction signifies that each value carries with it a behavior - be that implied (you stick appropriate code in a case) or explicit (in the specific Command hierarchy class).
Thus it looks to me like a usage of the Command pattern is appropriate (though your sample doesnt prove it) - i.e., have a class (potentially a hierarchy using constructor overloads or any other [set of] factory mechanisms) that keeps the state associated with the request along with the specific behaviour. Then, instead of passing an Enum value, create an appropriate LogCommand instance to the logger, which just invokes it (potentially passing a Log Sink 'receptacle' which the Command can log into). Otherwise you're poking random subsets of parameters in different places.
SEEALSO related posts:
C# - Is there a better alternative than this to ‘switch on type’?
Replace giant switch statement with what?
One possible solution is to use a SortedDictionary:
delegate void EnumHandler (args);
SortedDictionary <Enum, EnumHandler> handlers;
constructor
{
handlers = new SortedDictionary <Enum, EnumHandler> ();
fill in handlers
}
void SomeFunction (Enum enum)
{
EnumHandler handler;
if (handlers.TryGetValue (enum, out handler))
{
handler (args);
}
else
{
// not handled, report an error
}
}
This method does allow you to replace the handlers dynamically. You could also use a List as the value part of the dictionary and have multiple handlers for each enum.
Try to use reflection.
Decorate enum options with attributes that holds associated value and return this value.
Create static class of constants and use reflection for mapping enum-option to constant by name
hope this will help
Some times storing the options in a map is a good solution, you can externalize the configuration to a file too, not sure if it applies to your application.
Long code example here, and the final generic code is a little heavy (EDIT have added an extra example that eliminates the need for the angle brackets at the expense of some final flexibility).
One thing that this solution will give you is good performance - not quite as good as a straightforward switch statement, but each case statement becomes a dictionary lookup and method invocation, so still pretty good. The first call will get a performance penalty, however, due to the use of a static generic that reflects on initialisation.
Create an attribute and generic type as follows:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class DynamicSwitchAttribute : Attribute
{
public DynamicSwitchAttribute(Type enumType, params object[] targets)
{ Targets = new HashSet<object>(targets); EnumType = enumType; }
public Type EnumType { get; private set; }
public HashSet<object> Targets { get; private set; }
}
//this builds a cache of methods for a given TTarget type, with a
//signature equal to TAction,
//keyed by values of the type TEnum. All methods are expected to
//be instance methods.
//this code can easily be modified to support static methods instead.
//what would be nice here is if we could enforce a generic constraint
//on TAction : Delegate, but we can't.
public static class DynamicSwitch<TTarget, TEnum, TAction>
{
//our lookup of actions against enum values.
//note: no lock is required on this as it is built when the static
//class is initialised.
private static Dictionary<TEnum, TAction> _actions =
new Dictionary<TEnum, TAction>();
private static MethodInfo _tActionMethod;
private static MethodInfo TActionMethod
{
get
{
if (_tActionMethod == null)
{
//one criticism of this approach might be that validation exceptions
//will be thrown inside a TypeInitializationException.
_tActionMethod = typeof(TAction).GetMethod("Invoke",
BindingFlags.Instance | BindingFlags.Public);
if (_tActionMethod == null)
throw new ArgumentException(/*elided*/);
//verify that the first parameter type is compatible with our
//TTarget type.
var methodParams = _tActionMethod.GetParameters();
if (methodParams.Length == 0)
throw new ArgumentException(/*elided*/);
//now check that the first parameter is compatible with our type TTarget
if (!methodParams[0].ParameterType.IsAssignableFrom(typeof(TTarget)))
throw new ArgumentException(/*elided*/);
}
return _tActionMethod;
}
}
static DynamicSwitch()
{
//examine the type TTarget to extract all public instance methods
//(you can change this to private instance if need be) which have a
//DynamicSwitchAttribute defined.
//we then project the attributes and the method into an anonymous type
var possibleMatchingMethods =
from method in typeof(TTarget).
GetMethods(BindingFlags.Public | BindingFlags.Instance)
let attributes = method.GetCustomAttributes(
typeof(DynamicSwitchAttribute), true).
Cast<DynamicSwitchAttribute>().ToArray()
where attributes!= null && attributes.Length == 1
&& attributes[0].EnumType.Equals(typeof(TEnum))
select new { Method = method, Attribute = attributes[0] };
//create linq expression parameter expressions for each of the
//delegate type's parameters
//these can be re-used for each of the dynamic methods we generate.
ParameterExpression[] paramExprs = TActionMethod.GetParameters().
Select((pinfo, index) =>
Expression.Parameter(
pinfo.ParameterType, pinfo.Name ?? string.Format("arg{0}"))
).ToArray();
//pre-build an array of these parameter expressions that only
//include the actual parameters
//for the method, and not the 'this' parameter.
ParameterExpression[] realParamExprs = paramExprs.Skip(1).ToArray();
//this has to be generated for each target method.
MethodCallExpression methodCall = null;
foreach (var match in possibleMatchingMethods)
{
if (!MethodMatchesAction(match.Method))
continue;
//right, now we're going to use System.Linq.Expressions to build
//a dynamic expression to invoke this method given an instance of TTarget.
methodCall =
Expression.Call(
Expression.Convert(
paramExprs[0], typeof(TTarget)
),
match.Method, realParamExprs);
TAction dynamicDelegate = Expression.
Lambda<TAction>(methodCall, paramExprs).Compile();
//now we have our method, we simply inject it into the dictionary, using
//all the unique TEnum values (from the attribute) as the keys
foreach (var enumValue in match.Attribute.Targets.OfType<TEnum>())
{
if (_actions.ContainsKey(enumValue))
throw new InvalidOperationException(/*elided*/);
_actions[enumValue] = dynamicDelegate;
}
}
}
private static bool MethodMatchesAction(MethodInfo method)
{
//so we want to check that the target method matches our desired
//delegate type (TAction).
//The way this is done is to fetch the delegate type's Invoke
//method (implicitly invoked when you invoke delegate(args)), and
//then we check the return type and parameters types of that
//against the return type and args of the method we've been passed.
//if the target method's return type is equal to or derived from the
//expected delegate's return type, then all is good.
if (!_tActionMethod.ReturnType.IsAssignableFrom(method.ReturnType))
return false;
//now, the parameter lists of the method will not be equal in length,
//as our delegate explicitly includes the 'this' parameter, whereas
//instance methods do not.
var methodParams = method.GetParameters();
var delegateParams = TActionMethod.GetParameters();
for (int i = 0; i < methodParams.Length; i++)
{
if (!methodParams[i].ParameterType.IsAssignableFrom(
delegateParams[i + 1].ParameterType))
return false;
}
return true;
}
public static TAction Resolve(TEnum value)
{
TAction result;
if (!_actions.TryGetValue(value, out result))
throw new ArgumentException("The value is not mapped");
return result;
}
}
Now do this in a Unit Test:
[TestMethod]
public void TestMethod1()
{
Assert.AreEqual(1,
DynamicSwitch<UnitTest1, Blah, Func<UnitTest1, int>>.
Resolve(Blah.BlahBlah)(this));
Assert.AreEqual(125,
DynamicSwitch<UnitTest1, Blah, Func<UnitTest1, int>>.
Resolve(Blah.Blip)(this));
Assert.AreEqual(125,
DynamicSwitch<UnitTest1, Blah, Func<UnitTest1, int>>.
Resolve(Blah.Bop)(this));
}
public enum Blah
{
BlahBlah,
Bloo,
Blip,
Bup,
Bop
}
[DynamicSwitchAttribute(typeof(Blah), Blah.BlahBlah)]
public int Method()
{
return 1;
}
[DynamicSwitchAttribute(typeof(Blah), Blah.Blip, Blah.Bop)]
public int Method2()
{
return 125;
}
So, given a value of TEnum, and your preferred 'action' type (in your code you would appear to be simply returning nothing and modifying the internal state of the class), you simply consult the DynamicSwitch<> class, ask it to resolve a target method, and then invoke it inline (passing the target object on which the method will be invoked as the first parameter).
I'm not really expecting any votes for this - it's a MAD solution to be honest (it does have the advantage of being able to be applied for any enum type, and even discreet values of type int/float/double, as well as supporting any delegate type) - so perhaps it's a bit of a sledgehammer!
EDIT
Once you have a static generic like this, angle-bracket hell ensues - so we want to try and get rid of them. A lot of the time, this is done by type inference on method parameters etc - but we have a problem here that we can't easily infer a delegate's signature without repeating the method call i.e. (args) => return.
However, you seem to require a method that takes no parameters and returns void, so you can close over this behemoth generic by fixing the delegate type to Action, and throw a fluid API into the mix as well (if that's your kind of thing):
public static class ActionSwitch
{
public class SwitchOn<TEnum>
{
private TEnum Value { get; set; }
internal SwitchOn(TEnum value)
{
Value = value;
}
public class Call<TTarget>{
private TEnum Value { get; set; }
private TTarget Target { get; set; }
internal Call(TEnum value, TTarget target)
{
Value = value;
Target = target;
Invoke();
}
internal void Invoke(){
DynamicSwitch<TTarget, TEnum, Action<TTarget>>.Resolve(Value)(Target);
}
}
public Call<TTarget> On<TTarget>(TTarget target)
{
return new Call<TTarget>(Value, target);
}
}
public static SwitchOn<TEnum> Switch<TEnum>(TEnum onValue)
{
return new SwitchOn<TEnum>(onValue);
}
}
Now add this to the test project:
[TestMethod]
public void TestMethod2()
{
//no longer have any angle brackets
ActionSwitch.Switch(Blah.Bup).On(this);
Assert.IsTrue(_actionMethod1Called);
}
private bool _actionMethod1Called;
[DynamicSwitch(typeof(Blah), Blah.Bup)]
public void ActionMethod1()
{
_actionMethod1Called = true;
}
Only issue with this (apart from the complexity of the solution :) ) is that you'd have to re-build this static wrapper type whenever you want to use a new type of target delegate for a dynamic switch elsewhere. You could generate a generic version based on the Action<...> and Func<...> delegates that incorporates TArg1, TArg(n) and TReturn (if Func<>) - but you'd end up writing a lot more code.
Perhaps I'll turn this into an article on my blog and do all of that - if I get the time!

Resolving a parameter name at runtime [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Finding the Variable Name passed to a Function in C#
In C#, is there a way (terser the better) to resolve the name of a parameter at runtime?
For example, in the following method, if you renamed the method parameter, you'd also have to remember to update the string literal passed to ArgumentNullException.
public void Woof(object resource)
{
if (resource == null)
{
throw new ArgumentNullException("resource");
}
// ..
}
One way:
static void Main(string[] args)
{
Console.WriteLine("Name is '{0}'", GetName(new {args}));
Console.ReadLine();
}
This code also requires a supporting function:
static string GetName<T>(T item) where T : class
{
var properties = typeof(T).GetProperties();
Enforce.That(properties.Length == 1);
return properties[0].Name;
}
Basically the code works by defining a new Anonymous Type with a single Property consisting of the parameter who's name you want. GetName() then uses reflection to extract the name of that Property.
There are more details here: http://abdullin.com/journal/2008/12/13/how-to-find-out-variable-or-parameter-name-in-c.html
Short answer: No, there isn't. (Is that terse enough? ;)
(EDIT: Justin's answer probably counts. It leaves a bad taste in my mouth, but it accomplishes the goal of "no need to put the parameter name into a string". I don't think I'd really count AOP though, as that's really changing to a completely different approach rather than answering the original question of getting a parameter name from within a method.)
Longer answer: There's a way to find out all the parameters of a method, but I don't think it's useful in this case.
Here's an example which displays the parameter names from a couple of methods:
using System;
using System.Reflection;
class Test
{
static void Main()
{
Foo(null);
Bar(null);
}
static void Foo(object resource)
{
PrintParameters(MethodBase.GetCurrentMethod());
}
static void Bar(object other)
{
PrintParameters(MethodBase.GetCurrentMethod());
}
static void PrintParameters(MethodBase method)
{
Console.WriteLine("{0}:", method.Name);
foreach (ParameterInfo parameter in method.GetParameters())
{
Console.WriteLine(" {0} {1}",
parameter.ParameterType,
parameter.Name);
}
}
}
So that does that, but if you have multiple parameters and you wanted to throw an appropriate exception, how would you know (in a safe way) which to use? Ideally you want something like:
public void Woof(object resource)
{
if (resource == null)
{
throw new ArgumentNullException(infoof(resource));
}
// ..
}
where the mythical infoof operator would return a ParameterInfo. Unfortunately this doesn't exist.
I dealt with this very same issue. There are a couple of ways of getting the parameter name but the most performant is to dip down into the IL. You can see an example of my implementation on my blog post on this very issue Taking the pain out of parameter validation.
The one caveat to this approach is you need to pass the parameter name in as a delegate but it is small price to pay for cleaner code:
public void SomeMethod(string value)
{
Validate.Argument(() => value).IsNotNull().IsNotEmpty();
}
Which is somewhat cleaner and clearer than:
public void SomeMethod(string value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (value == string.Empty)
{
throw new ArgumentException("Value cannot be an empty string.", "value");
}
}
The static method approach has allowed me to chain a number of methods together in a fluent interface. Initially an Argument object is returned which only allows a basic null test which returns a ReferenceArgument object which can then have additional validation. If the object under test is a value type then different tests are available.
The API allows for a number of common tests but it would be hard to capture all the possible tests so to provide flexibility a generic test method allows an expression or function to be provided and in the case of the former the expression can actually be used as the error message.
My example only covers a few of the basics but you can easily expand the interface to check for ranges and throw ArgumentOutOfRangeExceptions or test objects inherit from a specific base class or implement an interface. There are some similar implementations but I have not as yet seen any that get the parameter name.
You can get this information using AOP. You can define an intercept that is invoked before method execution and throw the exception there. This also takes care of the problem that null checking is a cross-cutting concern.
PostSharp is a good simple implementation of AOP.
Here's what your code would look like (haven't tested, but it should get you very close)
[AttributeUsage(AttributeTargets.Parameter)]
public class CanBeNullAttribute : Attribute
{
private readonly bool canBeNull;
public CanBeNullAttribute()
: this(true)
{
}
public CanBeNullAttribute(bool canBeNull)
{
this.canBeNull = canBeNull;
}
public bool AllowNull
{
get { return canBeNull; }
}
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class EnforceNullConstraintAttribute : OnMethodInvocationAspect
{
public override void OnInvocation(MethodInvocationEventArgs eventArgs)
{
object[] arguments = eventArgs.GetArgumentArray();
ParameterInfo[] parameters = eventArgs.Delegate.Method.GetParameters();
for (int i = 0; i < arguments.Length; i++)
{
if (arguments[i] != null) continue;
foreach (CanBeNullAttribute attribute in parameters[i].GetCustomAttributes(typeof(CanBeNullAttribute), true))
{
if (!attribute.AllowNull) throw new ArgumentNullException(parameters[i].Name);
}
}
base.OnInvocation(eventArgs);
}
}
Now, you can modify your method:
[EnforceNullConstraint]
public void Woof([CanBeNull(false)] object resource)
{
// no need to check for null, PostSharp will weave it at compile time
// execute logic assured that "resource" is not null
}
You might want:
1)
public static void ThrowIfNull<T>(Expression<Func<T>> expr)
{
if (expr == null || expr.Compile()() != null) //the compile part is slow
return;
throw new ArgumentNullException(((MemberExpression)expr.Body).Member.Name);
}
or
2)
public static void ThrowIfNull<T>(Expression<Func<T>> expr)
{
if (expr == null)
return;
var param = (MemberExpression)expr.Body;
if (((FieldInfo)param.Member).GetValue(((ConstantExpression)param.Expression).Value) == null)
throw new ArgumentNullException(param.Member.Name);
}
And call it:
Class.ThrowIfNull(() => resource);
But that's not what you would want probably. Its also a lot slower 1) is abt 1000 times slower than 2). May be:
3)
public static void ThrowIfNull<T>(this T item) where T : class
{
if (item == null)
return;
var param = typeof(T).GetProperties()[0];
if (param.GetValue(item, null) == null)
throw new ArgumentNullException(param.Name);
}
And call it:
new { resource }.ThrowIfNull();
Cleaner, much faster than above 2! :)
You can also extend these methods for properties of objects. For eg.,
new { myClass.MyProperty1 }.ThrowIfNull();
You can cache property values to improve performance further as property names don't change during runtime. See related question Finding the variable name passed to a function

Categories