I have a class Decision, with Fluent interface, that I use as follows:
Decision.Name("MyDecision").SetRule(new MyRule());
Internally Decision has a method Run that calls MyRule IsSatisfied method and pass 2 arguments: Data and DateType.
I would also like to be able to use the following alternative syntax to define the Rule:
Decision.Name("MyDecision").SetRule((data, dataType) => {
// Rule definition
// Return boolean result
});
How can I do this?
Definition Class
public class Definition {
private String _name;
private Rule rule;
public Definition(String name) {
_name = name;
}
public static Definition Name(String name) {
return new Definition(name);
}
public Definition SetRule(Rule rule) {
_rule = rule;
return this;
}
public bool Run(Data data, DataType dataType) {
return _rule.IsSatisfied(data, dataType);
}
}
Rule class
public abstract class Rule {
public abstract Boolean IsSatisfied(Data data, DataType dataType);
}
Your are expecting to receive a function or a delegate and convert it into a new Rule() instance, that is an abstract class.
The first problem is: you can not instantiate a abstract class. So unless you add a Type as parameter to SetRule OR make Rule class not abstract. It will not be possible.
The second problem is: It's not a problem, but a warning. Your Rule class has only one method. And your Definition class has one one Rule. If this is your real code, it will be more clear if the IsSatisfied method was inside the Definition class.
But your question is: How can I do this?
Definition.Name("MyDecision").SetRule((data, dataType) => {
// Rule definition
// Return boolean result
});
I'll provide an example about how to do this using Rule class not abstract.
First you need to make your rule class concrete an able to receive a function or an delegate in the constructor.
I'll use Func<> as Ian Kemp already provided an solution with delegate. I suggest you to use delegate for this kind of scenarios because it's better for maintainability.
public class Rule {
protected Func<Data, DataType, Boolean> _isSatisfied {get; set;}
// Deafult constructor is optional. I keep it just rise a correct type of exception in case any child class call IsSatisfied without set it first.
public Rule()
{
_isSatisfied = (data, dataType) => { throw new NotImplementedException(); }; // Or any default behavior you want.
}
// this contructor will provide the behavior you want.
public Rule(Func<Data, DataType, Boolean> isSatisfied)
{
_isSatisfied = isSatisfied;
}
// This method now is only a wrapper to our Func<>
public virtual Boolean IsSatisfied(Data data, DataType dataType)
{
return _isSatisfied(data, dataType);
}
}
Then add a new method on Definition class that receive our Func and create the rule.
public class Definition
{
private String _name;
private Rule _rule;
public Definition(String name) {
_name = name;
}
public static Definition Name(String name) {
return new Definition(name);
}
public Definition SetRule(Rule rule) {
_rule = rule;
return this;
}
// Works like a charm
public Definition SetRule(Func<Data, DataType, Boolean> func) {
_rule = new Rule(func);
return this;
}
public bool Run(Data data, DataType dataType) {
return _rule.IsSatisfied(data, dataType);
}
}
And if you and to create a specific Rule that overrides and implements its own IsSatisfied method you can do it like this.
public class MyRule : Rule {
public override Boolean IsSatisfied(Data data, DataType dataType)
{
Console.WriteLine("MyRule: Dataname:{0}, DataTypeName: {1}", data.DataName, dataType.DataTypeName);
return false;
}
}
And this is an small sample:
public class Program
{
public static void Main()
{
var data = new Data() { DataName = "My Data Name" };
var dataType = new DataType() { DataTypeName = "My Data Type Name" };
try
{
// Log-> MyRule: Dataname:My Data Name1, DataTypeName: My Data Type Name
Definition.Name("MyDecision").SetRule(new MyRule()).Run(data, dataType);
// Log -> Func: Dataname:My Data Name1, DataTypeName: My Data Type Name
Definition.Name("MyDecision").SetRule((dataArg, dataTypeArg) =>
{
Console.WriteLine("Func: Dataname:{0}, DataTypeName: {1}", dataArg.DataName, dataTypeArg.DataTypeName);
return false;
}).Run(data, dataType);
}
catch(Exception ex)
{
Console.WriteLine("Error: ", ex.Message);
}
}
}
You can run this sample on DotNetFiddle if you want.
If you are trying to create a generic rules engine I believe that you should give us more information about how you gonna implement your rules (On a new question).
You can also take a look on how this open sources rules engines works.
NRules
RulesChain
A nondestructive approach to achieve this is to create an extension method for Rule class. By the term nondestructive I mean an approach that does not modify the original architecture/concept of your code. In order to create an extension method, you have to first declare a static class. Then you have to define a method whose first parameter is pointing to the type of the target class (using this keyword). That said; you can implement what you need the following way:
public static class RuleExtensions {
public static Boolean SetRule (this Rule rule, Func<(Definition definition, Boolean result)> definitionFn) {
var fn = definitionFn();
rule.SetRule(fn.definition);
return fn.result;
}
}
Define a delegate typed to take in (Data data, DataType dataType) and return a bool, an internal (could also be private) class that wraps and executes that delegate, and finally a method on Definition to create and assign a new instance of the class.
public delegate bool RuleEvaluator(Data data, DataType dataType);
internal class InlineRule : Rule
{
private RuleEvaluator _ruleEvaluator;
public InlineRule(RuleEvaluator ruleEvaluator)
{
_ruleEvaluator = ruleEvaluator;
}
public override bool IsSatisfied(Data data, DataType dataType)
=> _ruleEvaluator(data, dataType);
}
public class Definition
{
... code as before...
public Definition SetRule(RuleEvaluator ruleEvaluator)
{
_rule = new InlineRule(ruleEvaluator);
return this;
}
}
Related
I have a generic method like this (simplified version):
public static TResult PartialInference<T, TResult>(Func<T, TResult> action, object param)
{
return action((T)param);
}
In the above, param is of type object on purpose. This is part of the requirement.
When I fill in the types, I can call it like this:
var test1 = PartialInference<string, bool>(
p => p.EndsWith("!"), "Hello world!"
);
However, I'd like to use type inference. Preferably, I would like to write this:
var test2 = PartialInference<string>(
p => p.EndsWith("!"), "Hello world!"
);
But this does not compile. The best I came up with is this:
var test3 = PartialInference(
(string p) => p.EndsWith("!"), "Hello world!"
);
The reason I would like to have this as a type parameter and still have the correctly typed return type is because my actual calls look something like this:
var list1 = ComponentProvider.Perform(
(ITruckSchedule_StaffRepository p) => p.GetAllForTruckSchedule(this)
)
Which is very ugly and I would love to write as something like this:
var list2 = ComponentProvider.Perform<ITruckSchedule_StaffRepository>(
p => p.GetAllForTruckSchedule(this)
)
You can split t into a generic method on a generic type:
class Foo<TOuter> {
public static void Bar<TInner>(TInner arg) {...}
}
...
int x = 1;
Foo<string>.Bar(x);
Here the int is inferred but the string is explicit.
What you are trying to achieve is not possible. You need to specify both generic arguments or none of the them if inference is possible.
You can use reflection... like this below
Here is an example of how to call a extension method with two generic parameters.
We have to ways to execute the extension method:
a) Directly from an abstract base class
b) From an instance object that derived from that base class
Not mandatory to implement like so, but I found it very handy.
a) You must supply the two generic arguments as usual.
b) You already have one of the generic types since you are using an instance. The other generic parameter must by passed as type argument, you cannot pass it a second generic parameter due to ambiguity.
(see How to pass 2 generics types into an extension method)
public interface IEntityDto
{
// Not relevant to this example, how is defined , is just an interface, it could be removed, if your generic types don't need interface constraints
}
public interface IRowVersion
{
// Not relevant to this example, how is defined , is just an interface, it could be removed, if your generic types don't need interface constraints
}
public interface IPropertyMappingValue
{
// Not relevant to this example, how is defined , is just an interface, it could be removed, if your returned object don't need interface constraints
string Value { get; set; }
}
public class PropertyMappingValue : IPropertyMappingValue
{
// Not relevant to this example, how is defined , is just an object, returned by our extension method
public string Value { get; set; }
}
public abstract class EntityBase
{
public static IPropertyMappingValue GetPropertyMappingValue<TEntity, TEntityDto>(string name) where TEntity : class, IRowVersion where TEntityDto : class, IEntityDto => EntityExtensions.GetPropertyMappingValue<TEntity, TEntityDto>(name);
}
// Sample Class
public class Entity : IRowVersion
{
}
// Sample Class
public class EntityDto : EntityBase, IEntityDto
{
}
public static class EntityExtensions
{
public static IPropertyMappingValue GetPropertyMappingValue<TEntityDto>(this TEntityDto instance, Type entityType, string name) where TEntityDto : class, IEntityDto
{
if (!typeof(IRowVersion).IsAssignableFrom(entityType))
throw new ArgumentException($"{entityType} do not implements {typeof(IRowVersion)}");
var method = typeof(EntityExtensions).GetMethod(nameof(GetPropertyMappingValue), new[] { typeof(string) });
var typeArgs = new[] { entityType, typeof(TEntityDto) };
var constructed = method?.MakeGenericMethod(typeArgs);
var result = constructed?.Invoke(null, new object[] { name });
return result as IPropertyMappingValue;
}
public static IPropertyMappingValue GetPropertyMappingValue<TEntity, TEntityDto>(string name) where TEntity : class, IRowVersion where TEntityDto : class, IEntityDto
{
//TO DO YOUR JOB HERE TO GET A VALID RETURNED OBJECT, as this is an example I will return a fake
// THE CODE IS JUST AN EXAMPLE of doing something with the types, but is not relevant for this example
//
var foo = typeof(TEntityDto);
var bar = typeof(TEntity);
//
return new PropertyMappingValue { Value = name }; // returning just a fake object
}
}
public class UnitTest
{
private readonly ITestOutputHelper _console;
public UnitTest(ITestOutputHelper console)
{
_console = console;
}
[Fact]
public void Test()
{
var oneWayOfExecuting = EntityBase.GetPropertyMappingValue<Entity, EntityDto>("Hello world"); //using a abstract base
_console.WriteLine(oneWayOfExecuting.Value);
var entityDto = new EntityDto();
var anotherWayOfExecuting = entityDto.GetPropertyMappingValue(typeof(Entity), "Hello world"); //using the extension method
_console.WriteLine(anotherWayOfExecuting.Value);
Assert.Equal("Hello world", oneWayOfExecuting.Value);
Assert.Equal("Hello world", oneWayOfExecuting.Value);
}
I have a situation where in, I would like to convert an Expression<Func<BaseType,object>> to Expression<Func<DerievedType,object>>
I am also open to other solutions as well for this particular scenario.
To demonstrate the problem, i have base class as following
public class PersonBase
{
public string Name{get;set;}
public virtual void Save()
{
Dummy.Method1(this,x=>x.Name);
}
}
Derieved Class is defined as
public class Student:PersonBase
{
public string School{get;set;}
}
The Dummy class and associated methods are defined as
public class Dummy
{
public static void Method1<TDestination>(TDestination value,params Expression<Func<TDestination,object>>[] selector)
{
var destinationType = value.GetType();
var selectorType = selector.GetType();
Console.WriteLine("Destination Type : " + destinationType.ToString());
Console.WriteLine("Selector Type : " +selectorType.ToString());
var FinalMethodToCallInfo = typeof(Dummy).GetMethod("FinalMethodToCall", BindingFlags.Public | BindingFlags.Static);
var FinalMethodToCallMethod = FinalMethodToCallInfo.MakeGenericMethod(destinationType);
FinalMethodToCallMethod.Invoke(null, new object[] { selector });
}
public static void FinalMethodToCall<TDestination>(params Expression<Func<TDestination,object>>[] selector)
{
Console.WriteLine("Finally here");
}
}
The whole example is demonstrated in the Fiddle here.
Since the destinationType in Method1 is of Type Student and selectorType is of type Expression>, I get an exception when i attempt to invoke the FinalMethodToCall using reflection.
Object of type 'System.Linq.Expressions.Expression`1[System.Func`2[PersonBase,System.Object]][]' cannot be converted to type 'System.Linq.Expressions.Expression`1[System.Func`2[Student,System.Object]][]'.
I am slightly lost here. One solution I could think of was to use ExpressionVisitor to replace the Expression Parameter Type from BaseClass to DerievedType.
But I was curious to know why, when calling the method from Base (and passing expression), I was pointing to two different types (Derieved and Base). Could someone guide me in understanding this behavior and also if there is a better solution than using ExpressionVisitor to replace the Parameter Type ?
PS: I cannot change signature of my Save Method.
I have made few changes to generic methods as below.
Update PersonBase and make Save method to explicitly declare T.
public class PersonBase
{
public string Name{get;set;}
public virtual void Save<T>() where T : PersonBase
{
Dummy.Method1<T>(this,x=>x.Name);
}
}
Update Method1's first parameter to be Object like below.
public static void Method1<TDestination>(Object value,params Expression<Func<TDestination,object>>[] selector)
And call your Save with explicitly passing generic value like as follow.
(new Student{Name="anu"}).Save<Student>();
So after implemented Page Object Pattern using this tutorial i have several
Pages that derived from BasePageElementMap.
And i want to handle some operation so i have this class:
public class DownloadAttachmentsHandler
{
public DownloadAttachmentsHandler(BasePageElementMap basePageElementMap)
{
Type type = basePageElementMap.GetType();
}
}
Every Pages that derived from BasePageElementMap have this html elements that locate inside its class that derived from BasePageElementMap and from this Page i have this Map object that contains all my HTML elements that i am using.
public class YahooEmailPage: BasePage<YahooEmailPageElementMap, YahooEmailPageValidator>...
so in case i am call this function like this:
UploadAttachmentsHandler att = new UploadAttachmentsHandler(new YahooEmailPage().Map);
I want to cast this into YahooEmailPage from my DownloadAttachmentsHandler method.
So currently i have this type object, how can i case it into YahooEmailPage ?
If I understood correctly, you want the following:
public class DownloadAttachmentsHandler
{
public static object Cast(object obj, Type t)
{
try
{
var param = Expression.Parameter(obj.GetType());
return Expression.Lambda(Expression.Convert(param, t), param)
.Compile().DynamicInvoke(obj);
}
catch (TargetInvocationException ex)
{
throw ex.InnerException;
}
}
public DownloadAttachmentsHandler(BasePageElementMap basePageElementMap)
{
Type type = basePageElementMap.GetType();
dynamic foo = Cast(basePageElementMap, type);
}
}
Based on this answer by balage.
EDIT: For the example, lets assume that GetType() returns the type bar. You will have to create a method like this one:
public static void UseDynamic(bar input)
{
// Stuff
}
And then do
public DownloadAttachmentsHandler(BasePageElementMap basePageElementMap)
{
Type type = basePageElementMap.GetType();
dynamic foo = Cast(basePageElementMap, type);
UseDynamic(foo);
}
You can use overloads to avoid having to write many ifs or a switch. However, whichever approach you take, you will have to create a method for each possible type.
I want to write a method that will analyze custom attributes of any method (with any number of arguments and any return type) knowing only method info.
This function will check if method has specific Attribute. like this: var tmp = methodInfo.GetCustomAttributes(typeof(LineItemAttribute),false); and if it has such attribute It will execute it.And I want to make call of that function really easy to use. So, in example there are three methods and method GetMethodAttributes that I want to call.
class Test
{
public static void Main()
{
}
public void Test1(){}
public void Test2(int a){}
public void Test3(object a, string c, Boolean d);
public void GetMethodAttributes(MethodInfo mi) {}
}
Ideally I want to write something like that
public static void Main()
{
var t = new Test();
GetMethodAttributes(t.Test1);
GetMethodAttributes(t.Test2);
GetMethodAttributes(t.Test3);
}
I don't want to use string representation of the method names as method names may change, like that:
MethodInfo info = type.GetMethod(name);
Do I have any options? Basically I need a way to use delegates for functions with different sinatures
As Chris Sinclair pointed out in the comment above; you can use a delegate without using reflection or expression trees to get the MethodInfo. The downside is that the compiler is not able to infer the generic parameter so you have to specify the delegate type to match the signature of the given method like this:
public class Test
{
public static void Main()
{
var t = new Test();
CheckMethodAttributes<Action>(t.Test1);
CheckMethodAttributes<Action<int>>(t.Test2);
CheckMethodAttributes<Action<object, string, bool>>(t.Test3);
}
public void Test1() { }
public void Test2(int a) { }
public void Test3(object a, string c, bool d) { }
public static void CheckMethodAttributes<T>(T func)
{
MethodInfo method = new MethodOf<T>(func);
// Example attribute check:
var ignoreAttribute = method.GetAttribute<IgnoreAttribute>();
if (ignoreAttribute != null)
{
// Do something here...
}
}
}
This uses two utility classes, the MethodOf<T> for extracting the MethodInfo from the given Delegate and some AttributeUtils to get strongly typed custom attribute retrieval:
public static class AttributeUtils
{
public static bool HasAttribute<TAttribute>(this MemberInfo member, bool inherit = true)
where TAttribute : Attribute
{
return member.IsDefined(typeof(TAttribute), inherit);
}
public static TAttribute GetAttribute<TAttribute>(this MemberInfo member, bool inherit = true)
where TAttribute : Attribute
{
return member.GetAttributes<TAttribute>(inherit).FirstOrDefault();
}
public static IEnumerable<TAttribute> GetAttributes<TAttribute>(this MemberInfo member, bool inherit = true)
where TAttribute : Attribute
{
return member.GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>();
}
}
public class MethodOf<T>
{
public MethodOf(T func)
{
var del = func as Delegate;
if (del == null) throw new ArgumentException("Cannot convert func to Delegate.", "func");
Method = del.Method;
}
private MethodInfo Method { get; set; }
public static implicit operator MethodOf<T>(T func)
{
return new MethodOf<T>(func);
}
public static implicit operator MethodInfo(MethodOf<T> methodOf)
{
return methodOf.Method;
}
}
You can do something like this using Expression Trees, where you pass the method via a lambda expression. You do still need to pass stub values for the parameters, however. For a good example of this in action, check out the source code for Moq, which uses this pattern extensively for setting up mock behaviors for unit testing. Just note that this is not a trivial thing to set up. If you need something relatively quick and dirty, your best bet is probably string names with a good refactoring tool and/or automated tests to help deal with the renaming issues.
I'm building some stuff out using Attributes. One thing I'd really like to implement as an attribute is a convert a string to this property's type using this function. Right now, I have this:
public delegate object ParameterConverter(string val);
[AttributeUsage(AttributeTargets.Property)]
public class ParameterConverterAttribute : ParameterBaseAttribute
{
ParameterConverter Converter;
public ParameterConverterAttribute(ParameterConverter converter)
{
Converter=converter;
}
public object Convert(string val)
{
return Converter(val);
}
}
And I use it like so:
public class Tester
{
[ParameterConverter(new ParameterConverter(TestConverter)] //error here
public int Foo{get;set;}
static object TestConverter(string val)
{
return 10;
}
}
However, .Net or at least C# doesn't appear to support this kind of thing. It appears that delegates inside of attributes doesn't work.
Is there any workarounds to this issue or a good way to deal with this problem?
No Delegates cannot be passed as an argument to an Attribute. The Supported types are :
Object
Type
Enum
Single Dimentional Array
bool, byte, float char, double, int, long, string .... etc.
But as it supports Type as well as strings, you can pass a Type and the name of the method to create a delegate inside the Attribute class.
public delegate object ParameterConverter(string val);
[AttributeUsage(AttributeTargets.Property)]
public class ParameterConverterAttribute : ParameterBaseAttribute
{
public ParameterConverter Converter { get; set; }
public ParameterConverterAttribute(Type delegateType, string method)
{
try{ // Important as GetMethod can throw error exception or return null
this.Converter = (ParameterConverter)Delegate.CreateDelegate(delegateType, delegateType.GetMethod(method));
}
catch { }
}
public object Convert(string val)
{
if(this.Converter != null)
return Converter(val);
}
}
And now you can use it like :
public class Tester
{
[ParameterConverter(typeof(ParameterConverter), "TestConverter"]
public int Foo{get;set;}
static object TestConverter(string val)
{
return 10;
}
}
I hope this would help you.
Lookup for TypeConverter class
or
Type Converter Example
This example shows how to create a type converter named AuthorConverter....The AuthorConverter example converts an Author object to a String and a String representation to an Author object.
UPDATE:
You can skip the limitations of attributes like #abhishek has shown.
Possible another way is to define some "convention over configuration": converter function is a method defined like so
private static Converter(string val) defined inside same class. In your case:
public class Tester
{
public int Foo{get;set;}
private static int FooConverter(string val)
{
return 10;
}
}
You can put some ParameterConverterAttribute on top of the property as a sign that custom converter function exists, but is not mandatory.