Filter Pattern with generic TypeOf











up vote
1
down vote

favorite












I'm implementing the filter (criteria) pattern and I'm not sure what the best approach is to create a generic TypeOfCriteria.



To give some context, part of the filtering system is specific, for example I have an EmailAddressContains filter inside a UserCriteria folder. The user class is abstract and there are several different usertypes inheriting from that base class, for example AdminUser and FullControlUser. Other parts of the system have similar inheritance trees. At first I implemented specific TypeOf criteria like TypeOfAdminUser, but I soon figured I could make this more generic.



I came up with three approaches and I'm not sure which is "the best". Or perhaps there's another approach which I haven't thought of yet.



Approach 1



public interface ICriteria<T> where T : BaseEntity
{
IEnumerable<T> MeetCriteria(IEnumerable<T> entities);
}

public class TypeOfCriteria<T> : ICriteria<T> where T : BaseEntity
{
private readonly Type _type;

public TypeOfCriteria(Type type)
{
_type = type;
}

public IEnumerable<T> MeetCriteria(IEnumerable<T> entities)
{
return from T entity in entities
where entity.GetType().Equals(_type)
select entity;
}
}


Usage:



ICriteria<User> criteria = new TypeOfCriteria<User>(typeof(AdminUser));
admins = criteria.MeetCriteria(users);


Approach 2



public interface ICriteria<T> where T : BaseEntity
{
IEnumerable<T> MeetCriteria(IEnumerable<T> entities);
}

public class TypeOfCriteria<T, TResult> : ICriteria<T>
where T : BaseEntity
where TResult : BaseEntity
{
public IEnumerable<T> MeetCriteria(IEnumerable<T> entities)
{
return entities.OfType<TResult>().Cast<T>();
}
}


Usage:



ICriteria<User> criteria = new TypeOfCriteria<User, AdminUser>();
admins = criteria.MeetCriteria(users);


Approach 3



public interface ICriteria<T> where T : BaseEntity
{
IEnumerable<T> MeetCriteria<TResult>(IEnumerable<T> entities);
}

public class TypeOfCriteria<T> : ICriteria<T> where T : BaseEntity
{
public IEnumerable<T> MeetCriteria<TResult>(IEnumerable<T> entities)
{
return entities.OfType<TResult>().Cast<T>();
}
}


Usage:



ICriteria<User> criteria = new TypeOfCriteria<User>();
admins = criteria.MeetCriteria<AdminUser>(users);


Pros & Cons



Approach 1 feels the most like my other Criteria classes, where I pass the actual criteria in the constructor (new EmailAddressContains(".com")).



The MeetCriteria implementation of Approach 2 feels a bit cleaner. I'm not sure about performance, this looks like it could be faster, but that's not really a metric that I worry about for this project.



I like Approach 3 the least, because it requires me to change the interface.










share|improve this question


















  • 1




    Its worth noting that method 1 can give different results to the other two. OfType will not just match on exact type but also match anything derived from its type. So for example if I do .OfType<Base>() that will return all types that are Base or are derived from Base. This may not be relevant in your specific case but it is worth keeping in mind.
    – Chris
    Nov 7 at 9:17










  • What is the purpose of putting all this in a separate class instead of using OfType directly, or writing an extension method that enhances its functionality? Seems like a pain to instantiate a class just to filter a list.
    – John Wu
    Nov 7 at 9:19






  • 2




    One other thing is that in approach2 you don't actually need the Cast due to covariance. ie IEnumerable<Derived> can be assigned to IEnumerable<Base>
    – Chris
    Nov 7 at 9:20






  • 2




    Approach 2 is fine, as it use generics all the way , is verifiable at compile time, there's not much difference between 2 & 3, but its preferred to have generic class or generic method, you are mixing both in Approach 3 and it doesn't have the constraint for the TResult
    – Mrinal Kamboj
    Nov 7 at 9:31






  • 1




    Looking at constraints should the constraint in 2 be TResult : T?
    – Chris
    Nov 7 at 9:33















up vote
1
down vote

favorite












I'm implementing the filter (criteria) pattern and I'm not sure what the best approach is to create a generic TypeOfCriteria.



To give some context, part of the filtering system is specific, for example I have an EmailAddressContains filter inside a UserCriteria folder. The user class is abstract and there are several different usertypes inheriting from that base class, for example AdminUser and FullControlUser. Other parts of the system have similar inheritance trees. At first I implemented specific TypeOf criteria like TypeOfAdminUser, but I soon figured I could make this more generic.



I came up with three approaches and I'm not sure which is "the best". Or perhaps there's another approach which I haven't thought of yet.



Approach 1



public interface ICriteria<T> where T : BaseEntity
{
IEnumerable<T> MeetCriteria(IEnumerable<T> entities);
}

public class TypeOfCriteria<T> : ICriteria<T> where T : BaseEntity
{
private readonly Type _type;

public TypeOfCriteria(Type type)
{
_type = type;
}

public IEnumerable<T> MeetCriteria(IEnumerable<T> entities)
{
return from T entity in entities
where entity.GetType().Equals(_type)
select entity;
}
}


Usage:



ICriteria<User> criteria = new TypeOfCriteria<User>(typeof(AdminUser));
admins = criteria.MeetCriteria(users);


Approach 2



public interface ICriteria<T> where T : BaseEntity
{
IEnumerable<T> MeetCriteria(IEnumerable<T> entities);
}

public class TypeOfCriteria<T, TResult> : ICriteria<T>
where T : BaseEntity
where TResult : BaseEntity
{
public IEnumerable<T> MeetCriteria(IEnumerable<T> entities)
{
return entities.OfType<TResult>().Cast<T>();
}
}


Usage:



ICriteria<User> criteria = new TypeOfCriteria<User, AdminUser>();
admins = criteria.MeetCriteria(users);


Approach 3



public interface ICriteria<T> where T : BaseEntity
{
IEnumerable<T> MeetCriteria<TResult>(IEnumerable<T> entities);
}

public class TypeOfCriteria<T> : ICriteria<T> where T : BaseEntity
{
public IEnumerable<T> MeetCriteria<TResult>(IEnumerable<T> entities)
{
return entities.OfType<TResult>().Cast<T>();
}
}


Usage:



ICriteria<User> criteria = new TypeOfCriteria<User>();
admins = criteria.MeetCriteria<AdminUser>(users);


Pros & Cons



Approach 1 feels the most like my other Criteria classes, where I pass the actual criteria in the constructor (new EmailAddressContains(".com")).



The MeetCriteria implementation of Approach 2 feels a bit cleaner. I'm not sure about performance, this looks like it could be faster, but that's not really a metric that I worry about for this project.



I like Approach 3 the least, because it requires me to change the interface.










share|improve this question


















  • 1




    Its worth noting that method 1 can give different results to the other two. OfType will not just match on exact type but also match anything derived from its type. So for example if I do .OfType<Base>() that will return all types that are Base or are derived from Base. This may not be relevant in your specific case but it is worth keeping in mind.
    – Chris
    Nov 7 at 9:17










  • What is the purpose of putting all this in a separate class instead of using OfType directly, or writing an extension method that enhances its functionality? Seems like a pain to instantiate a class just to filter a list.
    – John Wu
    Nov 7 at 9:19






  • 2




    One other thing is that in approach2 you don't actually need the Cast due to covariance. ie IEnumerable<Derived> can be assigned to IEnumerable<Base>
    – Chris
    Nov 7 at 9:20






  • 2




    Approach 2 is fine, as it use generics all the way , is verifiable at compile time, there's not much difference between 2 & 3, but its preferred to have generic class or generic method, you are mixing both in Approach 3 and it doesn't have the constraint for the TResult
    – Mrinal Kamboj
    Nov 7 at 9:31






  • 1




    Looking at constraints should the constraint in 2 be TResult : T?
    – Chris
    Nov 7 at 9:33













up vote
1
down vote

favorite









up vote
1
down vote

favorite











I'm implementing the filter (criteria) pattern and I'm not sure what the best approach is to create a generic TypeOfCriteria.



To give some context, part of the filtering system is specific, for example I have an EmailAddressContains filter inside a UserCriteria folder. The user class is abstract and there are several different usertypes inheriting from that base class, for example AdminUser and FullControlUser. Other parts of the system have similar inheritance trees. At first I implemented specific TypeOf criteria like TypeOfAdminUser, but I soon figured I could make this more generic.



I came up with three approaches and I'm not sure which is "the best". Or perhaps there's another approach which I haven't thought of yet.



Approach 1



public interface ICriteria<T> where T : BaseEntity
{
IEnumerable<T> MeetCriteria(IEnumerable<T> entities);
}

public class TypeOfCriteria<T> : ICriteria<T> where T : BaseEntity
{
private readonly Type _type;

public TypeOfCriteria(Type type)
{
_type = type;
}

public IEnumerable<T> MeetCriteria(IEnumerable<T> entities)
{
return from T entity in entities
where entity.GetType().Equals(_type)
select entity;
}
}


Usage:



ICriteria<User> criteria = new TypeOfCriteria<User>(typeof(AdminUser));
admins = criteria.MeetCriteria(users);


Approach 2



public interface ICriteria<T> where T : BaseEntity
{
IEnumerable<T> MeetCriteria(IEnumerable<T> entities);
}

public class TypeOfCriteria<T, TResult> : ICriteria<T>
where T : BaseEntity
where TResult : BaseEntity
{
public IEnumerable<T> MeetCriteria(IEnumerable<T> entities)
{
return entities.OfType<TResult>().Cast<T>();
}
}


Usage:



ICriteria<User> criteria = new TypeOfCriteria<User, AdminUser>();
admins = criteria.MeetCriteria(users);


Approach 3



public interface ICriteria<T> where T : BaseEntity
{
IEnumerable<T> MeetCriteria<TResult>(IEnumerable<T> entities);
}

public class TypeOfCriteria<T> : ICriteria<T> where T : BaseEntity
{
public IEnumerable<T> MeetCriteria<TResult>(IEnumerable<T> entities)
{
return entities.OfType<TResult>().Cast<T>();
}
}


Usage:



ICriteria<User> criteria = new TypeOfCriteria<User>();
admins = criteria.MeetCriteria<AdminUser>(users);


Pros & Cons



Approach 1 feels the most like my other Criteria classes, where I pass the actual criteria in the constructor (new EmailAddressContains(".com")).



The MeetCriteria implementation of Approach 2 feels a bit cleaner. I'm not sure about performance, this looks like it could be faster, but that's not really a metric that I worry about for this project.



I like Approach 3 the least, because it requires me to change the interface.










share|improve this question













I'm implementing the filter (criteria) pattern and I'm not sure what the best approach is to create a generic TypeOfCriteria.



To give some context, part of the filtering system is specific, for example I have an EmailAddressContains filter inside a UserCriteria folder. The user class is abstract and there are several different usertypes inheriting from that base class, for example AdminUser and FullControlUser. Other parts of the system have similar inheritance trees. At first I implemented specific TypeOf criteria like TypeOfAdminUser, but I soon figured I could make this more generic.



I came up with three approaches and I'm not sure which is "the best". Or perhaps there's another approach which I haven't thought of yet.



Approach 1



public interface ICriteria<T> where T : BaseEntity
{
IEnumerable<T> MeetCriteria(IEnumerable<T> entities);
}

public class TypeOfCriteria<T> : ICriteria<T> where T : BaseEntity
{
private readonly Type _type;

public TypeOfCriteria(Type type)
{
_type = type;
}

public IEnumerable<T> MeetCriteria(IEnumerable<T> entities)
{
return from T entity in entities
where entity.GetType().Equals(_type)
select entity;
}
}


Usage:



ICriteria<User> criteria = new TypeOfCriteria<User>(typeof(AdminUser));
admins = criteria.MeetCriteria(users);


Approach 2



public interface ICriteria<T> where T : BaseEntity
{
IEnumerable<T> MeetCriteria(IEnumerable<T> entities);
}

public class TypeOfCriteria<T, TResult> : ICriteria<T>
where T : BaseEntity
where TResult : BaseEntity
{
public IEnumerable<T> MeetCriteria(IEnumerable<T> entities)
{
return entities.OfType<TResult>().Cast<T>();
}
}


Usage:



ICriteria<User> criteria = new TypeOfCriteria<User, AdminUser>();
admins = criteria.MeetCriteria(users);


Approach 3



public interface ICriteria<T> where T : BaseEntity
{
IEnumerable<T> MeetCriteria<TResult>(IEnumerable<T> entities);
}

public class TypeOfCriteria<T> : ICriteria<T> where T : BaseEntity
{
public IEnumerable<T> MeetCriteria<TResult>(IEnumerable<T> entities)
{
return entities.OfType<TResult>().Cast<T>();
}
}


Usage:



ICriteria<User> criteria = new TypeOfCriteria<User>();
admins = criteria.MeetCriteria<AdminUser>(users);


Pros & Cons



Approach 1 feels the most like my other Criteria classes, where I pass the actual criteria in the constructor (new EmailAddressContains(".com")).



The MeetCriteria implementation of Approach 2 feels a bit cleaner. I'm not sure about performance, this looks like it could be faster, but that's not really a metric that I worry about for this project.



I like Approach 3 the least, because it requires me to change the interface.







c# generics software-design






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 7 at 9:06









Rik D

393




393








  • 1




    Its worth noting that method 1 can give different results to the other two. OfType will not just match on exact type but also match anything derived from its type. So for example if I do .OfType<Base>() that will return all types that are Base or are derived from Base. This may not be relevant in your specific case but it is worth keeping in mind.
    – Chris
    Nov 7 at 9:17










  • What is the purpose of putting all this in a separate class instead of using OfType directly, or writing an extension method that enhances its functionality? Seems like a pain to instantiate a class just to filter a list.
    – John Wu
    Nov 7 at 9:19






  • 2




    One other thing is that in approach2 you don't actually need the Cast due to covariance. ie IEnumerable<Derived> can be assigned to IEnumerable<Base>
    – Chris
    Nov 7 at 9:20






  • 2




    Approach 2 is fine, as it use generics all the way , is verifiable at compile time, there's not much difference between 2 & 3, but its preferred to have generic class or generic method, you are mixing both in Approach 3 and it doesn't have the constraint for the TResult
    – Mrinal Kamboj
    Nov 7 at 9:31






  • 1




    Looking at constraints should the constraint in 2 be TResult : T?
    – Chris
    Nov 7 at 9:33














  • 1




    Its worth noting that method 1 can give different results to the other two. OfType will not just match on exact type but also match anything derived from its type. So for example if I do .OfType<Base>() that will return all types that are Base or are derived from Base. This may not be relevant in your specific case but it is worth keeping in mind.
    – Chris
    Nov 7 at 9:17










  • What is the purpose of putting all this in a separate class instead of using OfType directly, or writing an extension method that enhances its functionality? Seems like a pain to instantiate a class just to filter a list.
    – John Wu
    Nov 7 at 9:19






  • 2




    One other thing is that in approach2 you don't actually need the Cast due to covariance. ie IEnumerable<Derived> can be assigned to IEnumerable<Base>
    – Chris
    Nov 7 at 9:20






  • 2




    Approach 2 is fine, as it use generics all the way , is verifiable at compile time, there's not much difference between 2 & 3, but its preferred to have generic class or generic method, you are mixing both in Approach 3 and it doesn't have the constraint for the TResult
    – Mrinal Kamboj
    Nov 7 at 9:31






  • 1




    Looking at constraints should the constraint in 2 be TResult : T?
    – Chris
    Nov 7 at 9:33








1




1




Its worth noting that method 1 can give different results to the other two. OfType will not just match on exact type but also match anything derived from its type. So for example if I do .OfType<Base>() that will return all types that are Base or are derived from Base. This may not be relevant in your specific case but it is worth keeping in mind.
– Chris
Nov 7 at 9:17




Its worth noting that method 1 can give different results to the other two. OfType will not just match on exact type but also match anything derived from its type. So for example if I do .OfType<Base>() that will return all types that are Base or are derived from Base. This may not be relevant in your specific case but it is worth keeping in mind.
– Chris
Nov 7 at 9:17












What is the purpose of putting all this in a separate class instead of using OfType directly, or writing an extension method that enhances its functionality? Seems like a pain to instantiate a class just to filter a list.
– John Wu
Nov 7 at 9:19




What is the purpose of putting all this in a separate class instead of using OfType directly, or writing an extension method that enhances its functionality? Seems like a pain to instantiate a class just to filter a list.
– John Wu
Nov 7 at 9:19




2




2




One other thing is that in approach2 you don't actually need the Cast due to covariance. ie IEnumerable<Derived> can be assigned to IEnumerable<Base>
– Chris
Nov 7 at 9:20




One other thing is that in approach2 you don't actually need the Cast due to covariance. ie IEnumerable<Derived> can be assigned to IEnumerable<Base>
– Chris
Nov 7 at 9:20




2




2




Approach 2 is fine, as it use generics all the way , is verifiable at compile time, there's not much difference between 2 & 3, but its preferred to have generic class or generic method, you are mixing both in Approach 3 and it doesn't have the constraint for the TResult
– Mrinal Kamboj
Nov 7 at 9:31




Approach 2 is fine, as it use generics all the way , is verifiable at compile time, there's not much difference between 2 & 3, but its preferred to have generic class or generic method, you are mixing both in Approach 3 and it doesn't have the constraint for the TResult
– Mrinal Kamboj
Nov 7 at 9:31




1




1




Looking at constraints should the constraint in 2 be TResult : T?
– Chris
Nov 7 at 9:33




Looking at constraints should the constraint in 2 be TResult : T?
– Chris
Nov 7 at 9:33

















active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53186327%2ffilter-pattern-with-generic-typeof%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown






























active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes
















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53186327%2ffilter-pattern-with-generic-typeof%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







這個網誌中的熱門文章

Tangent Lines Diagram Along Smooth Curve

Yusuf al-Mu'taman ibn Hud

Zucchini