I'm not having much luck searching for this answer, as I think that I don't know enough about the proper terms for it.
(Edit for clarity of code and how I call it)
I have a class that instantiates an extension method:
public static class Foo
{
public static IList<T> Bar<T>(this DataTable table) where T : class, new()
{
IList<T> list = ... // do something with DataTable.
return list;
}
}
I call this method like this:
DataTable table = SomehowGetTable();
IList<MyObject> list = table.Bar<MyObject>();
Again, greatly simplified.
Now, what I'd like to do, is add a delegate(?) so that after I get the list, I can call a method on each T in the list, like so:
public static class Foo
{
public static IList<T> Bar<T>(this DataTable table, MyDelegate postProcess)
{
IList<T> list = ... // do something with DataTable.
foreach(T item in list)
{
t.postProcess();
}
return list;
}
}
I don't know what I need to be able to pass in postProcess.. a delegate, a Predicate, or an Action, mostly because I'm Linq-challenged still.
Or, maybe this isn't even possible?
What you want is an Action< T > so you can do:
public static class Foo
{
public static IList<T> Bar(this DataTable table, Action<T> postProcess)
{
IList<T> list = ... // do something with DataTable.
foreach(T item in list)
{
postProcess(item);
}
return list;
}
}
First, you need to define Bar as generic, otherwise it won't compile.
Second, if you're trying to operate on each element within the list, you need to pass in a delegate that takes a single parameter of type T and returns no value. A built-in .NET delegate type is Action<T>, and it'll do fine.
So,
public static IList<T> Bar<T>(this DataTable table, Action<T> postProcess)
{
IList<T> list = ... // do something with DataTable
foreach(T item in list)
{
postProcess(item);
}
return list;
}
The signature would be
public static IList<T> Bar<T>(this DataTable table, Action<T> postProcess) {
var list = // Get ILIst<T> from DataTable
foreach (var i in list)
postProcess(i);
}
These days .Net brings virtually all method signatures to the table that you may ever need through Action and Func delegates. While action covers all void return type methods, Func introduces non-void returns.
Note that T must be defined as type argument on your method. The compiler may be able to infer T from the action you provide into the method:
List<double> myDoubles = table.Bar((double x) => Debug.Writeline(x));
For example if you are actually processing the values coming into a different type, the signature may look like :
public static IList<Z> Bar<T,Z>(this DataTable table, Func<T,Z> postProcess) {
return /* Get Listof T */ .Select(postProcess).ToList();
}
Used like
List<int> values = table.Bar((double d) => (int)d);
You can do either
public static IList<T> Bar<T>(this DataTable table, Action<T> postProcess)
{
...
postProcess(someT);
...
}
or add a generic constraint:
public static IList<T> Bar<T>(this DataTable table)
where T : IHasPostProcess
{
...
someT.postProcess();
...
}
Try Action<T>:
public static class Foo
{
public static IList<T> Bar(this DataTable table, Action<T> postProcess)
{
IList<T> list = ... // do something with DataTable.
foreach(T item in list)
{
postProcess(item);
}
return list;
}
}
Or use an interface so you do not have to pass action: (I prefer this one)
public interface IDo
{
Do();
}
public static class Foo
{
public static IList<T> Bar(this DataTable table) where T : IDo
{
IList<T> list = ... // do something with DataTable.
foreach(T item in list)
{
item.Do();
}
return list;
}
}
Related
I'm experimenting with extending classes and managed to extend List<T> for fun like so:
public static void SomeCustomSort<T>(this List<T> list, string item)
{
if (typeof(T) != typeof(string) || list.Count == 0)
return;
// doStuff();
}
I wondered if there was a smarter way to extend List<T> only for List<string> so that my extension method is not listed or accessable for any other type T
Just make your method non-generic:
public static void SomeCustomSort(this List<string> list, string item)
and specify exact type it should work with
NOTE: With void methods even if you want to restrict extension method parameter to some set of types (e.g. all implementors of some interface or some non-sealed class with classes derived from it) I would not recommend using generic method with parameter constraint:
public static void SomeCustomSort<T>(this List<T> animals)
where T: IAnimal
Why? Because it overcomplicates your code. Non-generic method is more simple to understand than generic method. Generic method without constraint is more simple to understand than generic method with constraint. You should start from the simplest solution which is easy to understand. What sounds more natural to you?
"It sorts list of animals"
"It sorts list of items of any type"
"It sorts list of items of any type which is animal"
When to use generic type constraint? When you return items from your method and you don't want to lose information about the exact type of list items. Consider method which returns animals by some weight filter
public static IEnumerable<IAnimal> WhereWeightBelow(this List<IAnimal> animals, int weight)
If you'll pass list of dogs to this method, you will lose intellisense for all dog-specific information in the method output.
dogs.WhereWeightBelow(10).Where(d => d. /* oops only IAnimal members here */)
Returning generic type will preserve all dog info for you.
Another alternative not yet mentioned:
public static void SomeCustomSort<T>(this List<T> list, string item)
where T: YourSpecificType
This allows you to specify more than just one type, for example:
public static void SomeCustomSort<T>(this List<T> list, string item)
where T: ISortable, ICustomInterface
Just specify T instead of making it a generic method.
public static void SomeCustomSort(this List<string> list, string item)
Just define exactly string type on your extension method
public static void SomeCustomSort(this List<string> list, string item)
{
// doStuff();
}
You can also use a constraint like this (in this example T would have to be of type Project):
public static void SomeCustomSort<T>(this List<T> list, string item)
where T : Project
{
}
I would show you in the following example how you can easily expand a generic list.
I expanded the list to return random data from the list itself.
We have a class for example:
public class ExampleClass
{
public string Name { get; set; }
}
We have now made a list of these classes in some method:
var exampleList = new List<ExampleClass>()
{
new ExampleClass()
{
Name = "Class1"
},
new ExampleClass()
{
Name = "Class2"
},
new ExampleClass()
{
Name = "Class3"
}
};
var randomList = exampleList.Random(2);
The following is a simple implementation of returning random objects from a list
public static class ListExtensions
{
public static IList<T> Random<T>(this IList<T> list, int numberOfResult) where T : class
{
if (list == null) throw new ArgumentNullException(nameof(list));
if (numberOfResult <= 0 || numberOfResult > list.Count) throw new ArgumentOutOfRangeException(nameof(numberOfResult));
var random = new Random();
var randomList = new List<T>();
var randomNumbers = new List<int>();
while (randomList.Count < numberOfResult)
{
var index = random.Next(list.Count);
if (randomNumbers.IndexOf(index) < 0)
{
randomNumbers.Add(index);
randomList.Add(list[index]);
}
}
return randomList;
}
}
I have an extension method that works on any class, but I want to call a special version if I am working on IEnumerable<T>.
For Example
public static class ExtensionMethods
{
public static dynamic Test<T>(this T source)
{
dynamic expandoObject = new System.Dynamic.ExpandoObject();
var dictionary = (IDictionary<string,object>)expandoObject;
dictionary["Test"] = source.ToString();
return dictionary;
}
public static IEnumerable<dynamic> Test<T>(this List<T> source)
{
var result = new List<dynamic>();
foreach(var r in source)
yield return r.Test();
}
public static IEnumerable<dynamic> Test<T>(this IEnumerable<T> source)
{
var result = new List<dynamic>();
foreach(var r in source)
yield return r.Test();
}
}
// Usage
public class X
{
string guid = Guid.NewGuid().ToString();
}
void Main()
{
List<X> list = new List<X>() { new X() };
list.Test().Dump(); // Correct but only works because there is an explicit overload for List<T>
var array = list.ToArray();
((IEnumerable<X>) array).Test().Dump(); // Correct
array.Test().Dump(); // Calls the wrong extension method
}
Is there any way I can get array.Test() to call the IEnumerable version without having to explicitly cast it?
Alternatively, if I give the extension method different names, if there any way I can get a compiler error if I accidently use the wrong one?
I think you are trying to solve it in a wrong direction. The List implements IEnumerable interface and as such the compiler can have problem with solving the best method will be invoked on List. What you could do -- you could test if the IEnumerable is a list inside the extension method.
public static IEnumerable<dynamic> Test<T>(this IEnumerable<T> source)
{
if (source is List<T>) {
// here
}
var result = new List<dynamic>();
foreach(var r in source)
yield return r.Test();
}
You can specify T and not rely on type inference, this will hint compiler to use correct extension method. Code would look like this:
var array = list.ToArray();
array.Test<X>().Dump();
What happens is, that compiler cannot tell which extension to use, since Array is valid argument for both method signatures:
public static dynamic Test<T>(this T source) { .. }
public static IEnumerable<dynamic> Test<T>(this IEnumerable<T> source) { .. }
In first case compiler can assume T is of type Array. Because of it, compiler has to picks one (might be first defined?).
Add this extension method to explicitly catch all array types:
public static IEnumerable<dynamic> Test<T>(this T[] source)
{
var result = new List<dynamic>();
foreach(var r in source)
yield return r.Test();
}
The following code with a boolean parameter works pretty well:
public List<T> SearchByStatus(bool status, List<T> list)
{
return (List<T>)list.Where(_item => _item.Executed == status);
}
But if I want to use something like this
public List<T> SearchByCodeType(ECodes codeType, List<T> list)
{
return (List<T>)list.Where(_item => _item.CodeType == codeType);
}
, the IDE throws an error saying Func<T, int, bool> doesn't accept 1 parameter.
I researched a bit and found for example this.
If I now add a seond parameter, lets say
public List<T> SearchByCodeType(ECodes codeType, List<T> list)
{
return (List<T>)list.Where((_item, _index) => _item.CodeType == codeType);
}
it says Func<T, bool> doens't accept 2 parameters.
The messages itself are correct, but I don't get why it assumes I want to use the overloaded version of Where in the first case and the non-overloaded in the second... Am I doing something wrong?
P.S.: The ECodes-type used is defined as
public enum ECodes : int
{
....
}
May that cause the issue?
Both of these should work fine:
public List<T> SearchByCodeType(ECodes codeType, List<T> list)
{
return list.Where((_item, _index) => _item.CodeType == codeType).ToList();
}
public List<T> SearchByCodeType(ECodes codeType, List<T> list)
{
return list.Where(_item => _item.CodeType == codeType).ToList();
}
If they don't - please check whether you have using System.Linq; at the top, and are using regular LINQ (not something obscure like LINQBridge).
You could also use:
public List<T> SearchByCodeType(ECodes codeType, List<T> list)
{
return list.FindAll(_item => _item.CodeType == codeType);
}
Note that all of this assumes that you have a suitable generic constraint on T such that T.CodeType is well-defined - presumably:
class Foo<T> where T : IHazCodeType
{
List<T> SearchByCodeType(ECodes codeType, List<T> list) {...}
}
interface IHazCodeType
{
ECodes CodeType {get;}
}
I'm struggling while trying to write generic methods to save and load data from a Sterling database.
This is my save method:
public static void SaveList<T>(List<T> listToSave)
{
foreach (T listItem in listToSave)
{
DatabaseInstance.Save(listItem);
}
}
I get squiggly red line under save and an error of "The Type T must be a reference type in order to use it as parameter T"
This is my load method:
public static List<T> LoadList<T>()
{
List<T> list = (from index in DatabaseInstance.Query<T, int>() select index.Key).ToList();
return list;
}
I get the same error.
Any ideas?
Cheers
Steve
UPDATE:
I added a where T : class as suggested and got an error:
The Type T must have a public parameterless constructor in order to use it as a parameter
Following instructions in the link provided by Bryan I added , new() on the end and all working now.
You need a generic type constraint on your definition:
public static void SaveList<T>(List<T> listToSave) where T : class
{
foreach (T listItem in listToSave)
{
DatabaseInstance.Save(listItem);
}
}
public static List<T> LoadList<T>() where T : class
{
List<T> list = (from index in DatabaseInstance.Query<T, int>() select index.Key).ToList();
return list;
}
To fix your code, you need a generic constraint that forces a reference type, as shown below. To set this answer out from others already posted, I also recommend that you use IEnumerable<T> rather than List<T>:
public static void SaveList<T>(IEnumerable<T> itemsToSave) where T : class
{
foreach (T item in itemsToSave)
{
DatabaseInstance.Save(listItem);
}
}
public static IEnumerable<T> LoadList<T>() where T : class
{
return (from index in DatabaseInstance.Query<T, int>()
select index.Key);
}
The change to IEnumerable<T> should be compatible with all your existing code, as List<T> already implements IEnumerable<T>. Used properly, this will also allow you get a nice performance boost by keeping fewer items at a time in RAM and make your code more powerful by allowing it to work with other collection types.
The problem is that, in your existing code, T can be anything. That's not OK because the Save function only accepts reference types.
You need to place a constraint which effectively makes a commitment to the compiler that T will be a reference type.
public static void SaveList<T>(List<T> listToSave) where T : class
{
foreach (T listItem in listToSave)
{
DatabaseInstance.Save(listItem);
}
}
can you try?
public static void SaveList<T>(List<T> listToSave) where T:class
{
foreach (T listItem in listToSave)
{
DatabaseInstance.Save(listItem);
}
}
Try adding a class constraint:
public static void SaveList<T>(List<T> listToSave) where T : class
{
foreach (T listItem in listToSave)
{
DatabaseInstance.Save(listItem);
}
}
public static List<T> LoadList<T>() where T : class
{
List<T> list = (from index in DatabaseInstance.Query<T, int>()
select index.Key).ToList();
return list;
}
I have a user defined class that I want to create a public List as part of. I want the List to be a List of delegate functions that I can add to and set each List Member to a delegate function. I want this list of functions to be part of the class I instantiate, so it follows the instance of the class as I pass it to other functions. I need the ability to call the delegated functions via a foreach loop, so it also has to be IEnumberable.
I've been trying for several hours, what I have may or may not do part of the job. When it started looking like I needed to write my own IEnumberation routines for the custom List, I realize I was in way over my head and came here.
This is the code I have:
public delegate List<ChartTestModel> MyDelegate<T>(T i);
public class DelegateList<T>
{
public void Add(MyDelegate<T> del)
{
imp.Add(del);
}
public void CallDelegates(T k)
{
foreach (MyDelegate<T> del in imp)
{
del(k);
}
}
private List<MyDelegate<T>> imp = new List<MyDelegate<T>>();
}
I don't even know if this does what I want it to or not. I know I can't ForEach through it, though. It's written entirely from pieced together code from looking on Google. I barely understand what it's supposed to do.
I don't see why you need a custom class at all. Just use List<T> where T is whatever delegate type.
List<Action> actions = new List<Action>();
actions.Add(() => blah blah);
actions.Add(Whatever); // Whatever() is a method
// now run them all
actions.ForEach(a => a());
IEnumerable<T> is simple to implement, particularly when you have a collection as a member of the class. All you need to do is define appropriate GetEnumerator methods, and the easiest thing to do is return the enumerator of the underlying collection.
class YourClass : IEnumerable<SomeClass>
{
List<SomeClass> list = ...
public IEnumerator<SomeClass> GetEnumerator()
{
return list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
Here, you implement methods for implicitly for IEnumerable<T> and explicitly for IEnumerable. (You have to implement both as IEnumerable<T> inherits IEnumerable.)
For your specific class, you might have
public class DelegateList<T> : IEnumerable<MyDelegate<T>>
{
// ...other class details
private List<MyDelegate<T>> imp = new List<MyDelegate<T>>();
public IEnumerator<MyDelegate<T>> GetEnumerator()
{
return imp.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
I hope this is userful to you.
static void Main(string[] args)
{
var delegateFuncs = new List<Func<string , string>> {
l1=>{ return "at1:" + l1;} ,
l2=>{ return "at2:" + l2;} ,
l3=>{ return "at3:" + l3;} ,
l4=>{ return "at4:" + l4;}
};
string parameter = "test";
foreach (var f in delegateFuncs)
{
Console.WriteLine(f(parameter));
}
Console.ReadLine();
}