Please look at the following method:
internal IEnumerable<Query> FilterOnUserInvolvement(IEnumerable<Query> input)
{
var user = _userManager.GetUserByADName(_user.Identity.Name);
if (_userManager.IsUserAdministrator(user) || _userManager.IsUserStaff(user))
{
return input;
}
else
{
using (var context = new QAContext())
{
var involvedQueries = context.UserInvolvement.Where(x => x.UserID == user.ID).Select(x => x.QueryID).ToList();
return input.Where(i => involvedQueries.Contains(i.ID));
}
}
}
Now this method takes IEnumerable<Query> and returns the same.
Actually the functionality of this method could be applied to any IEnumerable<Type> that holds ID.
How can I rewrite this query, using generics so it can be called with another Type that holds ID?
Just restrict your T to a type that contains ID:
internal IEnumerable<T> FilterOnUserInvolvement<T>(IEnumerable<T> input) where T : ISomeInterfaceWithId
{
}
Related
I am using Entity Framework and LINQ. I want to create a reusable method in a "helper" class for GridViews.
The method will return a DataSource as a List of entities based off the type of entity passed.
So GridView1 will show [Entity1]'s so the call will look like:
GridView1.DataSource = helperClass.GetDataSource(new Entity1());
Note* If I should pass the entity type I want as a string in the method I am open for suggestion. I just don't want to have to use a switch case between the ~40 entity types this method could return
The reusable method will be simple and look similar to:
public static object GetDataSource(object type)
{
using (DatabaseContext dc = new DatabaseContext())
{
if (dc.[how do I get the entity type here].Count() > 0)
{
var modelList = dc.[how do I get the entity type here also].ToList();
}
}
}
This will sound silly, but obviously I wasn't able to do:
var modelList = dc.(type.GetType()).ToList();
but that is basically what I want to accomplish.
If you want to bind the type at compile-time, you can pass the type as a generic argument, and use this type of method:
public DbSet<T> GetDataSource<T>()
{
var targetType = typeof(DbSet<T>);
return _db
.GetType()
.GetMethods()
.Where( m => m.ReturnType == targetType)
.Single()
.Invoke(_db, null) as DbSet<T>;
}
How does it work? Well, we don't know the name of the method that returns the entity that is being requested, but we do know that the return type has to be a DbSet<T>. So we scan the DatabaseContext for any method that returns that type, and invoke it. This assumes there is exactly one method that has that return type.
If you need true run-time binding (you can't supply the <T> parameter) you can use this sort of method. Note that the return type is just a general IEnumerable because you can't have a specific return type if it's not known at compile time. You can always cast it back to a DbSet<T> if needed.
public IEnumerable GetDataSource(Type type)
{
var targetType = typeof(DbSet<>).MakeGenericType(new Type[] { type });
return _db
.GetType()
.GetMethods()
.Where( m => m.ReturnType == targetType)
.Single()
.Invoke(_db, null) as IEnumerable;
}
Here is a full example. Note that I stubbed out the EF objects, but this example should still work with a real DbSet and DatabaseContext.
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
public class Program
{
public class DbSet<T> : List<T>
{
}
public class User
{
public string Name { get; set; }
public override string ToString()
{
return "User " + Name;
}
}
public class Transaction
{
public decimal Amount { get; set; }
public override string ToString()
{
return "Transaction " + Amount.ToString("0.00");
}
}
public class DatabaseContext
{
public DbSet<User> GetUsers()
{
return new DbSet<User>()
{
new User { Name = "Bob" },
new User { Name = "Alice" }
};
}
public DbSet<Transaction> GetTransactions()
{
return new DbSet<Transaction>()
{
new Transaction { Amount = 12.34M },
new Transaction { Amount = 56.78M }
};
}
}
public class HelperClass
{
private readonly DatabaseContext _db;
public HelperClass(DatabaseContext db)
{
_db = db;
}
public DbSet<T> GetDataSource<T>()
{
var targetType = typeof(DbSet<T>);
return _db
.GetType()
.GetMethods()
.Where( m => m.ReturnType == targetType)
.Single()
.Invoke(_db, null) as DbSet<T>;
}
public IEnumerable GetDataSource(Type type)
{
var targetType = typeof(DbSet<>).MakeGenericType(new Type[] { type });
return _db
.GetType()
.GetMethods()
.Where( m => m.ReturnType == targetType)
.Single()
.Invoke(_db, null) as IEnumerable;
}
}
public static void Main()
{
var helperClass = new HelperClass(new DatabaseContext());
foreach (var u in helperClass.GetDataSource<User>())
{
Console.WriteLine(u);
}
foreach (var t in helperClass.GetDataSource(typeof(Transaction)))
{
Console.WriteLine(t);
}
}
}
Output:
User Bob
User Alice
Transaction 12.34
Transaction 56.78
Full code on DotNetFiddle
This approach was not plausible and I ended up storing the datasource of the GridView in a SessionState variable. Saved having to requery for the DataSource each postback (could get tedious if I had to keep track of order bys when requerying. instead the sessionstate variable keeps the sort order)
How do I make this expression dynamic based on the generic type passed in the parameter?
In the simplified form:
public static class CompareService
{
public static List<T> Run<T>(List<T> database_list, string directory_path)
{
var csv_list = CompareService.MergeRecordsFromFiles<T>(directory);
return CompareService.RunComparison<T>(database_list, csv_list);
}
public static T CompareData<T>(List<T> database_list, List<T> csv_list)
{
var diff = new List<T>();
foreach (var db_item in database_list)
{
// ...
// if T is of type Deathstar compare reference_number property
// if T is of type Stormtrooper compare id property
// if T is of type Sith compare id and anger_level property
var csv_item = csv_list.FirstOrDefault(x => x.reference_number == db_item.reference_number);
// Comparison code
ComparisonResult result = compareLogic.Compare(db_item, csv_item);
// ...
}
return diff;
}
}
It is called from another generic service:
public static void Whatever<T>(List<T> list)
{
// ...
var directory_path = "C:\";
var delta = CompareService.CompareData<T>(list, directory_path);
// ...
}
The most naive implementation would be to check if your itemToFind can be cast to DeathStar, StormTrooper or Sith and if so call the instances property.
var deathStar = itemToFind as DeathStar;
if(deathStar != null)
return database_list.Where(x => ((DeathStar)x).reference_number == deathStar.reference_number).FirstOrDefault();
else
{
var sith = itemToFind as Sith;
if(sith != null)
return database_list.Where(x => ((Sith)x).anger_level == sith.anger_level).FirstOrDefault();
else
return database_list.Where(x => ((StormTrooper)x).id== ((StormTrooper)item).id).FirstOrDefault();
}
This is quite cumbersome, including many casts. In particular it completely bypasses the actual benefits of generics using any arbitrary type (that fullfills the constraints if existing). In your case you´d have a generic method that will only wortk for three decent types.
A better approach is to let all your classes implement a common interface that defines a property, for instance:
interface IObject {
int Level { get; }
}
Now all classes define that level-property:
clas DeathStar : IObject
{
public int Level { get { return this.reference_number; } }
}
clas Sith : IObject
{
public int Level { get { return this.anger_level; } }
}
clas StormTrooper: IObject
{
public int Level { get { return this.id; } }
}
Than you can use a constraint on your type T to implement that interface:
public static T CompareData<T>(List<T> list, T itemToFind) where T: IObject
Why not like this:
public static T CompareData<T>(List<T> list, Func<T, bool> predicate)
{
return database_list.FirstOrDefault(predicate);
}
And then use it like this:
var itemToFind = new ItemToFind();
var myObjectList = new List<MyObject>();
var item = CompareData<MyObject>(myObjectList, x=> x.MyObjectProperty == itemToFind.Id);
You could add a property selector:
public static class CompareService
{
public static T CompareData<T>(this List<T> list, T itemToFind, Func<T, int> propSelector)
{
int propToFind = propSelector(itemToFind); // cache
return database_list.FirstOrDefault(x => propSelector(x) == propToFind);
}
}
And call it like that:
listOfDeathstars.CompareData(deathStarToFind, ds => ds.reference_number);
listOfStormtroopers.CompareData(trooperToFind, t => t.id);
listOfSiths.CompareData(sithStarToFind, sith => new { sith.id, sith.anger_level});
Note: I added the this keyword in the signature to make it an extension (not sure if you intended that but forgot the keyword). And Where(predicate).FirstOrDefault() can be reduced to FirstOrDefault(predicate).
We are currently in the process of moving from RhinoMocks to NSubstitute.
I have a method that takes an object of type DatabaseParams. This class has the following structure (simplified):
public class DatabaseParams
{
public string StoredProcName { get; private set; }
public SqlParameter[] Parameters { get; private set; }
public DatabaseParams(string storeProcName, SqlParameter[] spParams)
{
StoredProcName = storeProcName;
Parameters = spParams;
}
}
I have the following method I want to check the arguments being passed to it are correct:
public interface IHelper
{
Task<object> ExecuteScalarProcedureAsync(DatabaseParams data);
}
How do I test that an instance of DatabaseParams was passed into that method with the correct values?
I could do this in RhinoMocks with something like this:
helperMock.Expect(m => m.ExecuteScalarProcedureAsync(Arg<DatabaseHelperParameters>.Matches(
p => p.StoredProcName == "up_Do_Something"
&& p.Parameters[0].ParameterName == "Param1"
&& p.Parameters[0].Value.ToString() == "Param1Value"
&& p.Parameters[1].ParameterName == "Param2"
&& p.Parameters[1].Value.ToString() == "Param2Value"
))).Return(Task.FromResult<DataSet>(null));
The helperMock is mocking the interface IHelper that contains the ExecuteScalarProcedureAsync method.
I've figured out the answer myself.
NSubstitute just needs to use the .Received() call and then when you specify your argument to the method. You can specify the argument matching as a predicate.
For example:
helperMock.Received().ExecuteScalarProcedureAsync(Arg.Is<DatabaseParams>(
p => p.StoredProcName == "up_Do_Something"
&& p.Parameters[0].ParameterName == "Param1"
&& p.Parameters[0].Value.ToString() == "Param1Value"
&& p.Parameters[1].ParameterName == "Param2"
&& p.Parameters[1].Value.ToString() == "Param2Value"));
An alternative is to use Do (see https://nsubstitute.github.io/help/actions-with-arguments/). I prefer this as it lets you call assertions against specific properties of the arguments, which gives you better feedback on which specific properties of the argument object are incorrect. For example:
StoredProc sp = null; // Guessing the type here
// Setup Do to capture arg
helperMock.ExecuteScalarProcedureAsync(Arg.Do<DatabaseParams>(p => sp = p));
// Call method
helperMock.ExecuteScalarProcedureAsync(dbParams);
// NUnit assertions, but replace with whatever you want.
Assert.AreEqual("up_Do_Something", sp.StoredProcName);
Assert.AreEqual("Param1", p.Parameters[0].ParameterName);
Assert.AreEqual("Param1Value", p.Parameters[0].Value.ToString());
Assert.AreEqual("Param2", p.Parameters[1].ParameterName);
Assert.AreEqual("Param2Value", p.Parameters[1].Value.ToString());
A bit late for the party, but ran into the same need.
I am working with mockito in java, and they have an Argument capture helper that I like.
It is basically the same as #Castrohenge answer
So here is my NSubstitute implementation.
public interface IFoo
{
void DoSomthing(string stringArg);
}
Argument capture class
public class ArgCapture<T>
{
private List<T> m_arguments = new List<T>();
public T capture()
{
T res = Arg.Is<T>(obj => add(obj)); // or use Arg.Compat.Is<T>(obj => add(obj)); for C#6 and lower
return res;
}
public int Count
{
get { return m_arguments.Count; }
}
public T this[int index]
{
get { return m_arguments[index]; }
}
public List<T> Values {
get { return new List<T>(m_arguments);}
}
private bool add(T obj)
{
m_arguments.Add(obj);
return true;
}
}
And the usage test case
[Test]
public void ArgCaptureTest()
{
IFoo foo1 = Substitute.For<IFoo>();
ArgCapture<string> stringArgCapture = new ArgCapture<string>();
foo1.DoSomthing("firstCall");
foo1.DoSomthing("secondCall");
foo1.Received(2).DoSomthing(stringArgCapture.capture());
Assert.AreEqual(2,stringArgCapture.Count);
Assert.AreEqual("firstCall",stringArgCapture[0]);
Assert.AreEqual("secondCall", stringArgCapture[1]);
}
I've created a class that works with my cache to get cached items. If the items are not cached then it calls a function to get the actual value.
This class has eight methods, all with almost identical code except for the function they call. I've created a function called GetObject which takes a delegate to call if it can't find an item in the class.
I can't get my code to compile because of the following error:
Argument 2: cannot convert from
'System.Collections.Generic.List<string>' to
'MyFunction<System.Collections.Generic.List<string>>'.
Am I doing something wrong or am I'm trying to do something that can't be done?
Here's the code I'm trying.
public delegate T MyFunction<T>(string s);
public T GetCultures<T>(string s) where T : class {
return NewListOfStrings(s) as T;
}
public List<string> NewListOfStrings(string s) {
return new List<string> { s };
}
public List<string> GetListOfStrings(string sitename) {
string key = cachingService.CreateValidKey("stringvalue");
//This is the line that fails to compile
var foundItems = GetObject<List<string>>(key,
GetCultures<List<string>>(sitename));
return foundItems;
}
public T GetObject<T>(string key, MyFunction<T> f) where T : class {
T foundItems = (T)cachingService.GetCachedItem(key);
if (foundItems == null) {
lock (key) {
foundItems = (T)cachingService.GetCachedItem(key);
if (foundItems == null) {
foundItems = f as T;
if (foundItems != null) {
cachingService.SetCachedItem(key, foundItems, 5,
Constants.MINUTES);
}
}
}
}
return foundItems;
}
Solution
public T GetObject<T>(string key, Func<T> getFromRepository) where T : class {
T foundItems = (T)cachingService.GetCachedItem(key);
if (foundItems == null) {
lock (key) {
foundItems = (T)cachingService.GetCachedItem(key);
if (foundItems == null) {
foundItems = getFromRepository() as T;
if (foundItems != null) {
cachingService.SetCachedItem(key, foundItems, 5,
Constants.MINUTES);
}
}
}
}
return foundItems;
}
public AreaModels.Site GetSiteByName(string sitename) {
string key = cachingService.CreateValidKey(
string.Format("Site_{0}", sitename));
return GetObject<AreaModels.Site>(key,
() => efRepository.GetSiteByName(sitename));
}
public List<AreaModels.Culture> GetCulturesForSite(string sitename) {
string key = cachingService.CreateValidKey(
string.Format("Cultures_{0}", sitename));
return GetObject<List<AreaModels.Culture>>(key,
() => efRepository.GetCulturesForSite(sitename));
}
public List<AreaModels.Resource> Resources(string sitename, int appId) {
string key = cachingService.CreateValidKey(
string.Format("ResourcesFor{0}", sitename));
return GetObject<List<AreaModels.Resource>>(key,
() => efRepository.GetResourcesBySiteAndAppId(sitename, appId));
}
You're passing the result of the function rather than the function itself. You can use a lambda like so:
var foundItems = GetObject<List<string>>(key,
name => GetCultures<List<string>>(sitename));
You also have this line:
foundItems = f as T;
Here you're trying to cast the function itself to its return type, which won't work. Instead you could do:
foundItems = f(name);
But now your problem is that you'd have to pass the name into GetObject, because otherwise it won't be accessible where it's needed. The reason for this is there's a mismatch between MyFunction, which takes a string, and what you actually want, which is a function that can be evaluated within GetObject without needing the name parameter to be passed in.
So what you should really do is change your delegate to:
public delegate T MyFunction<T>();
Or alternatively get rid of the delegate altogether and have the f parameter be a Func<T>.
With either of these options, you can pass in the lamba with no parameter required:
var foundItems = GetObject<List<string>>(key,
() => GetCultures<List<string>>(sitename));
And evaluate it like:
foundItems = f();
Note that it's a bit roundabout to create a lambda to pass it into another method just to then evaluate it, rather than just passing the result in directly. So unless there's some reason that you need to do this in some cases, you might instead want to change the f parameter to take a type T instead. In this case I suspect you're doing it to lazily evaluate the function so that you don't have to evaluate if the result is already cached. That would probably be a valid reason, assuming you're not optimizing for performance prematurely.
You aren't creating a delegate. You are actually evaluating the method before calling GetObject. Easily fixed:
var foundItems = GetObject<List<string>>(key,
name => GetCultures<List<string>>(name));
Note also that it isn't obvious what you want to do with sitename in this scenario; you might instead mean this:
name => GetCultures<List<string>>(sitename));
Here's a complete example
public class TestDelegate
{
//You don't need generic here if you always return a list of string
public List<string> GetCulture(string s)
{
return new List<string> { s };
}
public T GetObject<T>(string key, Func<string, T> fn)
{
T foundItems = fn(key);
return foundItems;
}
public void Test()
{
List<string> test = GetObject("abc", x => GetCulture(x));
}
}
If you look at the method Test() and GetObject(), you can note 3 interesting things :
You don't have to specify the generic type on GetObject() because the compiler infer it from GetCulture()
The x parameter serves as an input to your delegate function, that way the method
GetObject can use the "key" and pass it to the delegate function.
I replace your delegate function by "Func" with a string input and a List output.
I am using this function to get a list of groups
public static IEnumerable<QuizGroups> GetGroups(string sectorId)
{
var Quizes = _QuizDataSource.AllQuizGroups.Where(x => x.Subtitle == sectorId);
return Quizes;
}
But this returns all, I want to return the first group in the list.
How do i change the statement to get the first group?
You can use First or FirstOfDefault and return enumerable with single element:
public static IEnumerable<QuizGroups> GetGroups(string sectorId)
{
return new[]
{
_QuizDataSource.AllQuizGroups.FirstOrDefault(x => x.Subtitle == sectorId)
};
}
Also note:
If you plan to always return one element only, consider refactoring GetGroups method to return QuizGroups only.
AllQuizGroups property may be null. Add null-check for that property.
You should consider using C# Naming Conventions.
Local variable names should be Camel Cased; so it should be: var quizes.
Property _QuizDataSource should be renamed to QuizDataSource if it is public or _quizDataSource or quizDataSource if it is private.¹
¹ — It's a heat debate whether to use _ or not for private fields, read more at: https://stackoverflow.com/questions/1630844/c-sharp-member-variables-fields-naming-convention
Try First or FirstOrDefault.
public static IEnumerable<QuizGroups> GetGroups(string sectorId)
{
var Quizes = _QuizDataSource.AllQuizGroups.FirstOrDefault(x => x.Subtitle == sectorId);
return Quizes;
}
public static QuizGroups GetGroups(string sectorId)
{
return QuizDataSource.AllQuizGroups.FirstOrDefault(
x => x.Subtitle == sectorId);
}
or add an indexer to the collection class (assuming MyQuizGroupsCollection is the type of _QuizDataSource
public class MyQuizGroupsCollection: IEnumerable<QuizGroups>
{
// other stuff
public QuizGroups this[string sectorId]
{ get { return FirstOrDefault(x => x.Subtitle == sectorId); } }
}
... then you could simply write
var Quizes = _QuizDataSource[sectorId];