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;
}
Related
I'm trying to create a method that would allow a "method group" to be passed in. Basically this is for testing where I want to make sure that a method was called. FakeItEasy already allows for the following code
public static IAnyCallConfigurationWithReturnTypeSpecified<ReturnType> ReturnForMethod<SUT, ReturnType>(
this Fake<SUT> fake,
string methodName, ReturnType returnObj)
{
var call = fake.AnyCall().WithReturnType<ReturnType>().Where(s => s.Method.Name == methodName);
call.Returns(returnObj);
return call;
}
//Called using
new Fake<IDummyFactory>().ReturnForMethod(nameof(IDummyFactory.Create), testStr);
For cleaner code I'd prefer to write something like
public static IAnyCallConfigurationWithReturnTypeSpecified<ReturnType> ReturnForMethodF<SUT ,ReturnType>(
this Fake<SUT> fake,
MethodGroup method, ReturnType returnObj)
Basically the same way nameof works. Using a function so I would want the method called as follows
new Fake<IDummyFactory>().ReturnForMethod(s=> s.Create, testStr); --NoInvoke as just want method group
"Method group" is a concept that exists only in the language's syntax, there is no runtime type that corresponds to a method group.
Before I answer the question, you can just do this at callsite:
new Fake<IDummyFactory>().ReturnForMethod(nameof(s.Create), testStr);
I don't see any reason s => s.Create would be better or more readable than nameof(s.Create).
Now for the fun part. Method groups are convertible to compatible delegate types as governed by an impossibly complicated set of magic rules.
So we would be looking for a method with a signature of:
public static IAnyCallConfigurationWithReturnTypeSpecified<TReturnType> ReturnForMethod<TSUT, TDelegate, TReturnType>(
this Fake<TSUT> fake,
Expression<Func<TSUT, TDelegate>> methodGroupExpression,
TReturnType returnObject) where TSUT : class
where TDelegate : Delegate
We're working with Expressions, so we will have to create an ExpressionVisitor that traverses the Expression tree and looks for method calls on the appropriate type. For simplicity we are going to assume that you are always calling the method with just a single x => x.Foo expression. Assuming we have a visitor class that does this, the body of our method is straightforward:
public static IAnyCallConfigurationWithReturnTypeSpecified<TReturnType> ReturnForMethod<TSUT, TDelegate, TReturnType>(
this Fake<TSUT> fake,
Expression<Func<TSUT, TDelegate>> methodGroupExpression,
TReturnType returnObject) where TSUT : class
where TDelegate : Delegate
{
var visitor = new ExtractMethodNameExpressionVisitor<TSUT>();
var methodName = visitor.ExtractMethodName(methodGroupExpression);
if (methodName is null)
{
throw new InvalidOperationException();
}
var call = fake.AnyCall().WithReturnType<TReturnType>().Where(s => s.Method.Name == methodName);
call.Returns(returnObject);
return call;
}
The expression s => s.Create is enriched with some magical compiler generated code during compilation, which converts it to the appropriate delegate type. But the method group itself is nested somewhere in it as a ConstantExpression of type MethodInfo. Our visitor class will traverse the tree, find such an expression and save its name.
class ExtractMethodNameExpressionVisitor<T> : ExpressionVisitor
{
private string? _methodName;
public string? ExtractMethodName(Expression expression)
{
_methodName = null;
this.Visit(expression);
return _methodName;
}
protected override Expression VisitConstant(ConstantExpression node)
{
if (node.Type == typeof(MethodInfo) &&
node.Value is MethodInfo methodInfo &&
methodInfo.DeclaringType == typeof(T))
{
_methodName = methodInfo.Name;
}
return base.VisitConstant(node);
}
}
And now we can test this:
var fake = new Fake<IDummyFactory>();
fake.ReturnForMethod(s => s.Create, "testStr");
var result = fake.FakedObject.Create();
Console.WriteLine(result);
The unfortunate part is that this doesn't work. As of C#9 at least, delegate types are kind of a second-class citizen in the language, and generic type inference for them does not work. So the above ReturnForMethod call does not compile, because the compiler cannot infer that a function returning string and taking no arguments is actually Func<string>. So the callsite must look like this:
fake.ReturnForMethod<IDummyFactory, Func<string>, string>(s => s.Create, "testStr");
which makes this solution much less appealing. The good news is that, if I understand the proposals correctly, in C#10 (or maybe C#11 if the feature misses C#10's release window) this would work without the explicit type signature.
You can find the full working demo here.
I have a generic class that I wish to store in a collection. As such, I've gone down the usual approach of creating an abstract class that the generic inherits from, and adding the generic properties on top (nb: new to this approach, so possible I'm still doing something wrong).
The net result is, my generic class looks like:
public class DependencyDeclaration<TDependantHost, TDependant, TFoundationHost, TFoundation> : DependencyDeclaration {
public DependencyDeclaration(Expression<Func<TDependandHost, TDependant>> dependantRef, Expression<Func<TFoundationHost, TFoundation>> foundationRef, Expression<Func<TDependantHost, TFoundationHost>> foundationHostRef)
public Expression<Func<TDependantHost, TDependant>> DependantRef {get;private set;}
public Expression<Func<TDependantHost, TDependant>> FoundationRef {get;private set;}
public Expression<Func<TDependantHost, TDependant>> FoundationHostRef {get; private set;}
}
And the base class:
public abstract class DependencyDeclaration {
public string GetDependantName() {
// Some code to return the name of the leaf property from
// DependantRef, roughly akin to GetPropertyNameFromExpression
// in BindableObjectBase from
// http://www.pochet.net/blog/2010/07/02/inotifypropertychanged-automatic-dependent-property-and-nested-object-support/
var e = this
.GetType()
.GetProperties()
.Where(p=>p.Name=="DependantRef")
.First()
.GetValue(this) as Expression;
return GetPropertyName(e).Name; // GetPropertyName requires a Func<T,U>, so this doesn't work as is.
}
public string GetFoundationName(Expression e) {
// ... similar implementation to GetDependantName
}
public string GetFoundationHostName(Expression e) {
// ... similar implementation to GetDependantName
}
public object GetFoundationHostRef(object dependantHost, Expression e) {
// Evaluates this.FoundationHostRef via reflection against
// dependantHost.
// Will function based on the comment below about using
// LambdaExpression, so not that worried about this one.
// Something like, though:
var e = this
.GetType()
.GetProperties()
.Where(p=>p.Name=="DependantRef")
.First()
.GetValue(this) as LambdaExpression;
if (e == null)
return;
var foundationHostRefFunc = e.Compile()
return foundationHostRefFunc(dependantHost);
}
// Returns the PropertyInfo of a property via an Expression
// as provided [here][http://stackoverflow.com/a/672212/847721]
public GetPropertyInfo(Expression<Func<T, U>> targetExpression)
{
// ... Magic expression parsing stuff ...
}
}
A list of such declarations would be populated on static construction of classes supporting ISupportsDependencyManager by using e.g.
public class MyClassWithCalculatedProperties : ISupportsDependencyManager {
// MyPropertySource inherits from INotifyPropertyChanged
public object MyPropertySource {get;set;}
// Trite example calculated property. Obviously actual calculated
// properties could be arbitrary.
public int MyCalculatedProperty
{
get {
return MyPropertySource.SomeProperty + 50;
}
}
private static DependencyDeclaration MyCalculatedPropertyDependencies =
new DependencyDelcaration<MyClassWithCalculatedProperties, int, MyPropertySource, int>(
(dependantHost)=>dependantHost.MyCalculatedProperty,
(foundationHost)=>foundationHost.SomeProperty,
(dependantHost)=>dependantHost.MyPropertySource
);
static MyClassWithCalculatedProperties()
{
// Static constructor iterates over the properties in the type
// using DependencyManager and appends them to a list that
// DependencyManager maintains of DependencyDeclaration instances
//
// This is where I'm going to generate a list of DependencyDeclarations - see below.
DependencyManager
.RegisterDependencies(
typeof(MyClassWithCalculatedProperties)
);
}
public MyClassWithCalculatedProperties()
{
// Constructor for MyClassWithCalculatedProperties
// Attach event handlers that allow calculated properties to
// have notifications on them.
DependencyManager.AttachPropertyChangedHandlers(this)
}
}
// This isn't finished yet, so expect bugs in ANY event
// (not certain I'm using reflection right)
public class DependencyManager
{
private static ConcurrentDictionary<Type, ConcurrentBag<DependencyDeclaration>> _ParsedDependencies;
// This is where I need the abstract class and/or interface. It
// allows all DependencyDeclarations to co-exist in the same
// collection to avoid needing to parse the type using reflection
// more than once in a given program execution.
public static RegisterDependencies(Type targetType)
{
var dependencyDeclarations =
targetType
.GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)
.Where(fi => fi.FieldType == typeof(DependencyDeclaration))
.Select(fi => fi.GetValue(targetType));
ConcurrentBag<DependencyDeclaration> container = GetManagedDependencyContainer(targetType);
dependencyDeclarations
.Cast<DependencyDeclaration>()
.ToList()
.ForEach(d => container.Add(d));
}
/*
* Other methods of DependencyManager
*/
}
This presents me with two problems:
At the point when I need to invoke GetUonTExpression<T,U>, I don't know what T and U are (I'm sure they're buried in the arg to be passed, but not sure how to extract or invoke in any event). Probably via reflection, but not sure the specific bits of reflection to use.
If I actually want to evaluate the expression, I can't find a way to do so - the compile method is missing, probably because it's not know to be a Func expression. However, whilst I know it'll be a Func<>, and I know that Func<> will have two type args, I don't know how to specify that, as opposed to what those type args will be.
Anyone have an idea how to go about this?
NB that what I'm actually intending to do with these Expressions may come into it too. The actual class has 4 typeargs, and three expressions. All three are used as ways of specifying the name of a property (for property change notification purposes), but the 3rd also needs to be able to be compiled to provide me with a way of getting to the current value of the expression when evaluated against an object of type T. This means, in most cases I don't really care about the inner Func, just string that the Expression.Body's rightmost leaf evaluates to, but in one case at least, I do care about compiling and evaluating the Func.
NB2: This code is expected to run through a bunch of expressions every time objects using it are created, but it's NOT expected to be run after object creation - so I'm ok with reflection in principle.
EDIT: Updated code substantially to give a clearer idea of what this is used for.
Instead of using the non-generic Expression, use LambdaExpression, so you have access to the Parameters and to Compile. The Expression are all LambdaExpression (see the definition:
public sealed class Expression<TDelegate> : LambdaExpression
)
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.
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!
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