one generic class create generic extension with expression<T,bool> method - c#

My code is as follows:
public partial class WhereHelper<T1> { }
public static partial class WhereHelperExtension
{
public static T Where<T,T1>(this T t, Expression<Func<T1,bool>> where) where T : WhereHelper<T1>
{
//do something....
return t;
}
}
public class Test
{
public void Main()
{
WhereHelper<DateTime> dt = new WhereHelper<DateTime>();
dt.Where(t => t.Year == 2016);//this is error
dt.Where<WhereHelper<DateTime>, DateTime>(t => t.Year == 2016);//this is success
}
}
Extension method I want to be like this:
WhereHelper<DateTime> dt = new WhereHelper<DateTime>();
dt.Where(t => t.Year == 2016);//this is error
how to create generic extension with Expression method.
Visual Studio does not recognize the "Where" extension methods.

In C#, if you need to provide any generic argument, you must provide them all. where constraints do not provide hints to the type resolver, and so it's impossible to decide what T1 is.
Change your signature to the following:
public static WhereHelper<T> Where<T>(this WhereHelper<T> t, Expression<Func<T,bool>> where)
{
return t;
}
Here, we know exactly what T, purely from the first argument, and so we do not have to explicitly specific the arguments.

Related

Generics & static classes. Implement query helper method

Currently we implement a mapping service like this (the service uses automapper, and we make use of the projection feature on it for this part)
// Injected
// IGenericRepository<Entity> entityRepo
var query = this.entityRepo
.FindAll(a => a.Id == someId)
.Take(1);
var result = this.mappingService
.Map<Entity, EntityDto>(query)
.FirstOrDefault();
I'd like to create an extension that would allow me to do the following
var result = this.entityRepo
.FindAll(a => a.Id == someId)
.Take(1).Map<EntityDto>() <--- Entity inferred from repo type
.FirstOrDefault();
My current attempt:
public static class IQueryableExtensions
{
private static IMappingService mappingService;
// will need to be called in app initialization
public static void InitialiseMapper(IMappingService service)
{
mappingService = service;
}
public static IEnumerable<TDto> Map<TAttribute, TDto>(this IQueryable<TAttribute> value)
where TDto : class
where TAttribute : IEntity
{
return mappingService.Map<TAttribute, TDto>(value);
}
}
Thus currently my implementation would look like this.
var result = this.entityRepo
.FindAll(a => a.Id == someId)
.Take(1).Map<Entity,EntityDto>()
.FirstOrDefault();
Questions:
1) How would i go about inferring the entity type from the IQueryable object
2) I realize i cant create a constructor that takes parameters, when creating a static class. Is the way i init the mapper the best/only way?
I tried that with reflection. The constraints are only for demo. If you want to call the reflection code multiple times be sure to cache the final methodinfo.
void Main()
{
var a = new Entity[] {new Entity { name = "a"},new Entity { name = "b"}};
Console.WriteLine(a.Take(1).Map<EntityDto>());
}
public class Entity
{
public string name;
}
public class EntityDto
{
public string dtoname;
}
public static class EntityExtensions
{
public static IEnumerable<U> Map<T,U>(this IEnumerable<T> e) where T: Entity where U: EntityDto, new()
{
foreach(var a in e)
{
yield return new U() { dtoname = a.name };
}
}
public static IEnumerable<U> Map<U>(this IEnumerable<object> e)
{
var method = typeof(EntityExtensions).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.Name == "Map" && m.GetGenericArguments().Length == 2)
.Single();
method = method.MakeGenericMethod(e.GetType().GetGenericArguments()[0], typeof(U));
return method.Invoke(null, new object[] { e}) as IEnumerable<U>;
}
}
1) Currently, you simply can't do that in C#. The type inference is not good enough. You can either specify all type parameters or none of them.
Edit: If you really want the version with a single parameter, you have to delete the second type parameter, type the parameter as non-generic IQueryable and deal with it. One way of doing that would be to determine the generic IQueryable<T> type at runtime. However, this requires reflection. In the case of IQueryable, you can also use the query provider to get around the reflection.
2) You can use a static type constructor.
public static class MyExtensions {
static MyExtensions() {
//initialization goes here
}
}
This type constructor is even called thread-safe. However, if you manage to throw an exception here, you cannot access the MyExtensionsclass!

Multiple generic types in same list and calling their methods

I'm making an object validation framework in my spare time to learn a few things and maybe use it for some school projects.
I have my generic Rule class, which looks something like this :
class Rule<T>
{
string propertyName;
Func<T, bool> ruleLambda;
bool IsBroken(T value)
{
return ruleLambda(value);
}
}
An object that would be validated would look a bit like this :
class Example
{
List<Rule<?>> MyRules; // can take all types of rules
List<Rule<T>> Validate<T>(string propertyName, T value)
{
List<Rule<T>> brokenRules = new List<Rule<T>>();
foreach (Rule rule in MyRules.Where(r => r.propertyName == propertyName))
{
if (rule.IsBroken(value))
brokenRules.Add(rule);
}
return brokenRules;
}
}
Where the T value argument would be the value of one of the Example class's properties, which can be of any type.
The Validate<T> method is called whenever a property is set.
The problem lies with the class's list of rules. Specifically the List<Rule<?>> line above. I want to store all the rules for a given class in the same list.
Alas, C# doesn't have a wildcard for generic types like in Java.
How should I do this?
A non-generic interface or base class utilizing objects instead of T could work, but how would I call the generic Rule's IsBroken method and not the non-generic one?
I would store your rules as object inside the Example class and use Enumerable.OfType<T> to find the matching rules for a given type:
class Example
{
private List<object> rules;
List<Rule<T>> Validate<T>(string propertyName, T value)
{
return this.rules.OfType<Rule<T>>()
.Where(r => r.PropertyName == propertyName && r.IsBroken(value))
.ToList();
}
}
In cases where I've needed something like this, I use interfaces or non-generic base classes. For example, you could create an interface:
public interface IRule
{
//non-generic properties & methods
}
public class Rule<T> : IRule
{
//implementation
}
then create a list of the interfaces:
private List<IRule> MyRules;
If you want to make converting from the interface to the generic easy, you could add an extension method:
public static Rule<T> ToGeneric<T>(this IRule rule)
{
return rule as Rule<T>;
}
I've tried a few things and I've found something that works pretty well for my needs. I have Rule<T> inherit from a base abstract rule class, with a generic IsBroken method:
abstract class Rule
{
string propertyName;
Func<object, bool> objectRule;
bool IsBroken<T>(T value)
{
Rule<T> rule = this as Rule<T>;
if (rule == null)
return objectRule(value);
return rule.IsBroken(value);
}
}
As you can see, I try to convert the base class to its generic counterpart using the generic type parameter in the IsBroken method.
Also, when creating a Rule<T> instance, I send a Func<object, bool> to its base class protected constructor:
public Rule(string propertyName, Func<T, bool> ruleLambda)
: base(propertyName, ConvertToObjectFunc(ruleLambda))
{
}
With the conversion method looking like this:
static Func<object, bool> ConvertToObjectFunc(Func<T, bool> func)
{
return new Func<object, bool>(o => func((T)o));
}
However, if it can't cast o to type T, it crashes. So I wrote this... thing:
static Func<object, bool> ConvertToObjectFunc(Func<T, bool> func)
{
return new Func<object, bool>
(
o =>
{
try
{
T obj = (T)o;
return func(obj);
}
catch { return true; } // rule is broken by default
}
);
}
It's pretty ugly, but it works. Hope this can help anybody else.

How can I add this method as an extension method to properties of my class?

I have a method and I want to add this method as an extension method to properties of my class.
This method give an expression as input parameter. The method is like below :
public static string GetPropertyName<T>(Expression<Func<T>> propertyExpression)
{
return (propertyExpression.Body as MemberExpression).Member.Name;
}
I want to use this method like below example :
string propertyName = MyClass.Property1.GetPropertyName();
Is it possible? if yes, what is the solution?
No, it's not possible to do that. It's not clear whether MyClass is the name of a class (and Property1 is a static property) or whether it's an instance property and MyClass.Property1 simply isn't a valid member access. If it's the latter, you probably want to change your method to something like:
public static string GetPropertyName<TSource, TResult>(
Expression<Func<TSource, TResult>> propertyExpression)
{
return (propertyExpression.Body as MemberExpression).Member.Name;
}
and call it as:
string propertyName = GetPropertyName<MyClass, string>(x => x.Property1);
Or you could use a generic class with a generic method, so that string can be inferred:
string propertyName = PropertyUtil<MyClass>.GetPropertyName(x => x.Property1);
That would be something like:
public static class PropertyUtil<TSource>
{
public static string GetPropertyName<TResult>(
Expression<Func<TSource, TResult>> propertyExpression)
{
return (propertyExpression.Body as MemberExpression).Member.Name;
}
}
Extension methods are type-specific (even when they are generic), you can't have an extension method for a property without having the same extension method available to all items that are of that type.
If you have an extension method for a specific type, it won't matter if it's a Property or a local variable or a class member, the extension method will still be availabe.
You can't create "static" extension methods.
Extension methods are "instance" methods.
You could just provide a helper class:-
string propertyName = PropertyHelper.GetPropertyName(() => instanceOfMyClass.Property1);
I'm clearly not an expert like Jon but this seems to me that what you want and is fairly simple (that's why I doubt, since Jon is clearly a reference person ! ;-)) :
class Program
{
static void Main(string[] args)
{
MyClass<int> myClass = new MyClass<int>();
string property1Name = myClass.Property1.GetPropertyName();
string property2Name = myClass.Property2.GetPropertyName();
}
}
public static class Extensions
{
public static string GetPropertyName<T>(this Expression<Func<T>> propertyExpression)
{
return (propertyExpression.Body as MemberExpression).Member.Name;
}
}
public class MyClass<T>
{
public Expression<Func<T>> Property1; //Sample with MyClass being generic
public Expression<Func<string>> Property2; //Sample which works anyway, MyClass being generic or not
}
It compiles and meet the requirements, from what I can see. You probably should have found it yourself, since you spoke about an extension method from start...

How can I write a generic anonymous method?

Specifically, I want to write this:
public Func<IList<T>, T> SelectElement = list => list.First();
But I get a syntax error at T. Can't I have a generic anonymous method?
Nope, sorry. That would require generic fields or generic properties, which are not features that C# supports. The best you can do is make a generic method that introduces T:
public Func<IList<T>, T> SelectionMethod<T>() { return list => list.First(); }
And now you can say:
Func<IList<int>, int> selectInts = SelectionMethod<int>();
Of course you can, but T must be known:
class Foo<T>
{
public Func<IList<T>, T> SelectionMethod = list => list.First();
}
As an alternative you could use a generic method if you don't want to make the containing class generic:
public Func<IList<T>, T> SelectionMethod<T>()
{
return list => list.First();
}
But still someone at compile time will need to know this T.
You declared only the return type as generic.
Try this:
public Func<IList<T>, T> SelectionMethod<T>() { return list => list.First(); }
The name of the thing you are declaring must include the type parameters for it to be a generic. The compiler supports only generic classes, and generic methods.
So, for a generic class you must have
class MyGeneric<T> {
// You can use T here now
public T MyField;
}
Or, for methods
public T MyGenericMethod<T>( /* Parameters */ ) { return T; }
You can use T as the return parameter, only if it was declared in the method name first.
Even though it looks like the return type is declared before the actual method, the compiler doesn't read it that way.
public static void SomeContainerFunction()
{
const string NULL_VALUE = (string)null;
Type GetValueType<T>(T value) => value?.GetType() ?? typeof(T);
var typeOfNullValue = GetValueType(NULL_VALUE);
Debug.WriteLine($"Value: {NULL_VALUE}, Type: {typeOfNullValue}");
}

Class type inference from static method / caller?

Given the following two classes:
public class ABC
{
public void Accept(Ordering<User> xyz)
{
// Do stuff with xyz...
}
}
public class Ordering<TEntity>
where TEntity : class
{
private readonly Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> Transform;
private Ordering(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> transform)
{
this.Transform = transform;
}
public static Ordering<TEntity> By<TKey>(Expression<Func<TEntity, TKey>> expression)
{
return new Ordering<TEntity>(query => query.OrderBy(expression));
}
public static Ordering<TEntity> ByDescending<TKey>(Expression<Func<TEntity, TKey>> expression)
{
return new Ordering<TEntity>(query => query.OrderByDescending(expression));
}
public Ordering<TEntity> ThenBy<TKey>(Expression<Func<TEntity, TKey>> expression)
{
return new Ordering<TEntity>(query => this.Transform(query).ThenBy(expression));
}
public Ordering<TEntity> ThenByDescending<TKey>(Expression<Func<TEntity, TKey>> expression)
{
return new Ordering<TEntity>(query => this.Transform(query).ThenByDescending(expression));
}
public IOrderedQueryable<TEntity> Apply(IQueryable<TEntity> query)
{
return Transform(query);
}
}
Used in the following way:
ABC abc = new ABC();
abc.Accept(Ordering<User>.By(u => u.Id));
Is there any way to infer the type of T like so:
abc.Accept(Ordering.By(u => u.Id));
You can do it, but not in a generic type. Generic type inference like this only occurs for generic methods. Declare a separate non-generic type, with a generic method:
public class XYZ
{
public static XYZ Action<T, TKey> (TKey key, T element)
{
return new XYZ<T>(element);
}
}
EDIT: Responding to the question edit.
No, you can't do something like this:
abc.Accept(Ordering.By(u => u.Id));
The problem is the inner expression:
Ordering.By(u => u.Id)
What's the type of u here? It could be any class with an Id property. Note that the C# compiler will need to work out the type of this expression before it looks at abc.Accept. Even if abc.Accept only worked for an Ordering<User>, it would fail.
There are three options here:
Use a static method in the generic class, specifying the source type argument explicitly, and inferring the key type argument:
Ordering<User>.By(u => u.Id)
Use a generic method in a non-generic class, specifying both type arguments explicitly:
Ordering.By<User, string>(u => u.Id)
Use a generic method in a non-generic class, specifying the type of the lambda parameter explicitly, and letting the compiler infer the key type argument:
Ordering.By((User u) => u.Id)
Obviously, all of these cases require you to specify the type explicitly somewhere.
One other option which is a little bit weird is relevant if you've typically already got an instance of User (or at least a variable of that type). You can use that as a sort of example, which gets ignored:
public static Ordering<T> By<T,TKey>(Expression<Func<T, TKey>> func, T example)
{
return By<T, TKey>(func);
}
...
Ordering.By(u => u.Id, dummyUser);

Categories