How to implement a "convert using this function" custom attribute in .Net? - c#

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.

Related

Converting Expression<Func<BaseType,object>> to Expression<Func<DerievedType,object>>>

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>();

Define method in method call

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;
}
}

Why members cannot be accessed by generic type?

I don't understand what am I doing wrong when trying to access members of class from generic type T. I also specifically used WHERE constraint.
I get the following message: 'T' is a type parameter, which is not valid in the current context.
class Test
{
public static int id = 1;
public int GetId()
{
return id;
}
}
public class TestUsage
{
public int IncrementId<T>() where T : Test
{
return 1 + T.GetId();
}
}
Since in public int IncrementId<T>(T test) the type parameter T could just be any type, C# has no clue which members this type has. You can add a generic type constraint. A way to do this, is to define an interface that types must implement to be used as type argument.
public interface IHasId
{
int GetId();
}
class Test : IHasId
{
public static int id = 1;
public int GetId()
{
return id;
}
}
public int IncrementId<T>(T item) where T : IHasId
{
return item.GetId() + 1;
}
Another option is to pass a property accessor to the method
public int IncrementId<T>(T item, Func<T, int> getId)
{
return getId(item) + 1;
}
You would call it with
int nextId = IncrementId(test, t => t.GetId());
See also:
Pass property itself to function as parameter in C#
My answer to the question How can I find a specific element in a List? explains that you should not use a method GetId but instead should use a property in C#.
Declaring the method as generic means that you can pass an argument of the generic type. So you could do this:
public class TestUsage
{
public int IncrementId<T>(T test) where T : Test
{
return 1 + test.GetId();
}
}
The generic type argument T doesn't mean anything unless something with that type is used either as an input argument, a return value, a variable of type T within the method, or some combination.
You do not provide an instance of T. Try:
public int IncrementId<T>(T t) where T : Test
{
return 1 + t.GetId();
}

c# - Cast with GetType() and reflection

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.

C# - No implicit reference conversion from 'T' to 'System.IComparable<T>'

I have taken the following class from another SO question:
public class Range<T> where T : IComparable<T>
{
public T Minimum { get; set; }
public T Maximum { get; set; }
public override string ToString() { return String.Format("[{0} - {1}]", Minimum, Maximum); }
public Boolean IsValid() { return Minimum.CompareTo(Maximum) <= 0; }
public Boolean ContainsValue(T value)
{
return (Minimum.CompareTo(value) <= 0) && (value.CompareTo(Maximum) <= 0);
}
}
I would like, however, to create another class that contains many instances of this class, and can execute a foreach loop on them all, returning true if the number passed is contained in any one of the ranges:
public class Ranges<T> where T : Range<T>
{
private List<Range<T>> rangelist;
public void add(Range<T> range)
{
rangelist.Add(range);
}
public Boolean ContainsValue(T value)
{
foreach (Range<T> range in rangelist)
{
if (range.ContainsValue(value)) return true;
}
return false;
}
}
However, i am getting the error The type 'T' cannot be used as type parameter 'T' in the generic type or method 'Range<T>'. There is no implicit reference conversion from 'T' to 'System.IComparable<T>'.
What exactly is going wrong here?
You don't seem to need the constraint where T : Range<T>
Just repeat the comparable constraint:
public class Ranges<T> where T : IComparable<T>
{
}
If you rewrite your second class slightly, you'll see why:
public class Ranges<U> where U : Range<U>
{
private List<Range<U>> rangelist;
public void add(Range<U> range)
{
rangelist.Add(range);
}
...
}
The error is telling you the compiler does not know if U is convertible to IComparable<U>, which is apparent from the declaration of Ranges<U> and Range<T> (Range<T> does not implement any interfaces).
More importantly, you have a recursing generic argument!
If U is Range<U>, then your class looks like Ranges<Range<T>> where T is U, and so on and so forth.
From what I can tell, you're not looking to write:
Ranges<Range<int>> x = ...;
But rather:
Ranges<int> x = ...;
Which would mean:
public class Ranges<T> where T : IComparable<T>
{
private List<Range<T>> rangelist;
...
You don't need new classes for that, use linq.
list1.All(x=>list2.Any(y=>y == x))
UPDATE: You are saying : I would like, however, to create another class that contains many instances of this class, and can execute a foreach loop on them all, returning true if the number passed is contained in any one of the ranges:
So effectively you have list of lists. Or more generally IEnumerable of IEnumerables.
There is enough standard generic data structures to handle this scenario
public static class ListOfListExtention {
public static bool ContainAny( this List<List<int>> lists, int number ) {
return lists.Any(l=>l.Any(x=>x == number))
}
}
Which can be rewritten in more generic way using IComparable interface
public static class ListOfListExtention {
public static bool ContainAny<T>
(this List<List<int>> lists, int value ) where T : IComparable<T> {
return lists.Any(l=>l.Any(x=>x == value))
}
}
So to compare with accepted answer, why wrap List in new class if you can just have one extension method.

Categories