1
votes

If i have:

public static Func<SomeType, bool> GetQuery() {
 return a => a.Foo=="Bar";
}

and a generic version

public static Func<T, bool> GetQuery<T>() {
 return (Func<T,bool>)GetQuery();
}

Is there a way to cast my strongly typed Func of SomeType to a Func of T? The only way I have found so far is to try and combine it with a mock function:

Func<T, bool> q=a => true;
return (Func<T, bool>)Delegate.Combine(GetQuery(), q);

I know how to do that with Expression.Lambda, but I need to work with plain functions, not expression trees

EDIT - using .net 3.5 Using Matthews examples, and with explicit detail of usage.

What I am after still though is how can I get from Func Of concreteType to Func Of T when returning a value.

I am just wanting to get past the compiler error - and am happy to have the potential for T to be a different type and throw a runtime error.

public interface ISecureEntity {
 Func<T,bool> SecureFunction<T>(UserAccount user);
}


public class Product : ISecureEntity {
 public Func<T,bool> SecureFunction<T>(UserAccount user) {
  return (Func<T,bool>)SecureFunction(user); //this is an invalid cast
 }
 public static Func<Product,bool> SecureFunction(UserAccount user) {
  return f => f.OwnerId==user.AccountId;
 }
 public string Name { get;set; }
 public string OwnerId { get;set; }
}


public class ProductDetail : ISecureEntity {
 public Func<T,bool> SecureFunction<T>(UserAccount user) {
  return (Func<T,bool>)SecureFunction(user); //this is an invalid cast
 }
 public static Func<ProductDetail,bool> SecureFunction(UserAccount user) {
  return pd => Product.SecureFunction(user)(pd.ParentProduct);
 }
 public int DetailId { get;set; }
 public string DetailText { get;set; }
 public Product ParentProduct { get;set; }
}

Then consumption in a repository:

public IList<T> GetData<T>() {
 IList<T> data=null;
 Func<T,bool> query=GetSecurityQuery<T>();
 using(var context=new Context()) {
  var d=context.GetGenericEntitySet<T>().Where(query);
  data=d.ToList();
 }
 return data;
}
private Func<T,bool> GetSecurityQuery<T>() where T : new() {
  var instanceOfT = new T();
        if (typeof(Entities.ISecuredEntity).IsAssignableFrom(typeof(T))) {
            return ((Entities.ISecuredEntity)instanceOfT).SecurityQuery<T>(GetCurrentUser());
        }
        return a => true; //returning a dummy query
    }
}
2
Unfortunately, I don’t understand what you’re trying to accomplish.Konrad Rudolph
Which version of .Net? That is fairly important here.Dykam
have updated above to make clearer. Using .net 3.5 trying to cast Func<SomeType,bool> to a Func<T,bool> At runtime T will be of type SomeType, but I want to have a interface that declares: Func<T,bool> GetQuery<T>();steve
Why don't you give us a usage example instead of trying to find way that something won't work (the only vaild input for T would be Foo in your example. If you replace the cast with Doo() as Func<T, bool> it will compile... but it will still only work with Foo.Matthew Whited
hope the extra detail explains better - I was trying to keep things abstract to avoid confusion on the implementation - but clearly that wasnt the case and just caused more confusion.steve

2 Answers

2
votes

I'm not totally sure what you are asking, but here's a shot in the dark...

public interface IFoo
{
    string Foo { get; set; }
}
public static Func<T, bool> GetQuery<T>()
    where T : IFoo
{
    return i => i.Foo == "Bar";
}
// example...
public class SomeType : IFoo
{
    public string Foo { get; set; }
}
public static Func<SomeType, bool> GetQuery()
{
    return GetQuery<SomeType>();
}
1
votes

For anyone who comes across this and wants to know the solution I ended up with there are 2 parts. Thanks for the help above and questioning of my sanity / what I was trying to do.

For what I was trying to do should have been using Expressions, and not delegate functions. I had only gone down the delegate route to allow me to pass in context into the sub query / expression.

To use Expressions with the ability to pass in a variable from an existing expression (sort of sub expressions) I used LinqKit.Invoke.

My end classes look like:

public interface ISecureEntity {
 Func<T,bool> SecureFunction<T>(UserAccount user);
}


public class Product : ISecureEntity {
 public Expression<Func<T,bool>> SecureFunction<T>(UserAccount user) {
  return SecureFunction(user) as Expression<Func<T,bool>>; 
 }
 public static Expression<Func<Product,bool>> SecureFunction(UserAccount user) {
  return f => f.OwnerId==user.AccountId;
 }
 public string Name { get;set; }
 public string OwnerId { get;set; }
}


public class ProductDetail : ISecureEntity {
 public Expression<Func<T,bool>> SecureFunction<T>(UserAccount user) {
  return SecureFunction(user) as Expression<Func<T,bool>>; 
 }
 public static Func<ProductDetail,bool> SecureFunction(UserAccount user) {
  return pd => Product.SecureFunction(user).Invoke(pd.ParentProduct);
 }
 public int DetailId { get;set; }
 public string DetailText { get;set; }
 public Product ParentProduct { get;set; }
}

Usage:

public IList<T> GetData<T>() {
 IList<T> data=null;
 Expression<Func<T,bool>> query=GetSecurityQuery<T>();
 using(var context=new Context()) {
  var d=context.GetGenericEntitySet<T>().Where(query);
  data=d.ToList();
 }
 return data;
}
private Expression<Func<T,bool>> GetSecurityQuery<T>() where T : new() {
  var instanceOfT = new T();
        if (typeof(Entities.ISecuredEntity).IsAssignableFrom(typeof(T))) {
            return ((Entities.ISecuredEntity)instanceOfT).SecurityQuery<T>(GetCurrentUser());
        }
        return a => true; //returning a dummy query
    }
}