This question already has answers here:
Adding new method to List<T> over object from which is made of
(3 answers)
Closed 1 year ago.
I know this is a bit odd and I do know another way to work around this but I was wonder if it is possible to have a method that would affect a list of itself. I'll explain.
This would be my workaround
public class Example
{
public void Sanitize()
{
// Does logic sanitize itself using API
}
public static List<Example> Sanitize(List<Example> examples)
{
/// returns a list of sanitized Examples
}
}
How the Example would be able to work on its own.
// Base Example sanitized
Example example = new Example(...);
example.Sanitize();
What I would also like to do
// Whole list sanitized
List<Example> examples = new List<Example> {...};
examples.Sanitize();
Is there a way to do that instead of being required to do this?
List<Example> startingExamples = new List<Example> { ... }
List<Example> endingExamples = Example.Sanitize(startingExamples);
You can have your static method iterate and mutate the list elements in place.
public class Example
{
public void Sanitize()
{
// Does logic sanitize itself using API
}
public static void Sanitize(List<Example> examples)
{
foreach (var example in examples)
{
example.Sanitize();
}
}
}
Note that you cannot modify the list itself while iterating it, but you can make changes to the elements of the list.
Looks like you could use an extension method.
Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are static methods, but they're called as if they were instance methods on the extended type. For client code written in C#, F# and Visual Basic, there's no apparent difference between calling an extension method and the methods defined in a type.
An extension method is a static method on a static class that is visible to the code that is using it. For example, public code. The first parameter of the method is the type that the method operates on and must be preceded with the this modifier.
So, for example, you could do something like this...
public static class EnumerableOfExampleExtensions
{
public static void Sanitize(this IEnumerable<Example> examples) /*or List is fine*/
{
// Null checks on examples...
foreach (var example in examples)
{
example.Sanitize();
}
}
}
Then you can call it as an instance method on any IEnumerable<Example>.
List<Example> examples = new List<Example>();
examples.Sanitize();
You can use an extension method to add functionality to the list.
static class ExtensionMethods
{
public static void Sanitize(this List<Example> source)
{
foreach (var item in source) item.Sanitize();
}
}
Now you can do this:
var list = new List<Example>();
list.Sanitize();
Related
I have some code at my job that uses ASP.net (which I have never touched) but I need to sort it. Here is the ListBox that I need to sort by Dscrp:
foreach (InteractiveInfo template in ddlsource)
{
Product thisProduct = FindProduct(template.UProductId);
if (thisProduct != null)
{
ddlProducts.Items.Add(
new ListItem(
string.Format("{0} ({1})", thisProduct.Dscrp, thisProduct.UProductId),
template.UProductId.ToString(CultureInfo.InvariantCulture)));
}
}
ddlProducts.DataBind();
}
I found this link:
https://gist.github.com/chartek/1655779
so I tried adding this at the end:
ddlProducts.Items.Sort();
but it just gives me this error:
Does not contain a definition for 'Sort'
If your application is on .NET 3.5 or above, take a look at MSDN: Extension Methods.
The tutorial link you provided is making use of the extension method concept where Sort() method is decorated onto ListItemCollection (i.e. ddlProducts.Items) type.
The extension methods should be defined inside non-generic static class. So the tutorial missing a class definition. You can try with:
public static class ExtensionsMethods //Notice the static class
{
public static void Sort(this ListItemCollection items)
{
//... Implement rest of logic from the tutorial
}
// Other extension methods, if required.
}
Hope this help you.
Use something like this its not perfect but update it as per your requirement
public static void Sort(this ListItemCollection items)
{
var itemsArray = new ListItem[items.Count];
items.CopyTo(itemsArray,0);
Array.Sort(itemsArray, (x, y) => (string.Compare(x.Value, y.Value, StringComparison.Ordinal)));
items.Clear();
items.AddRange(itemsArray);
}
Consider the following method example:
public static string[] ParseOptions()
{
return Environment.GetCommandLineArgs();
}
What would I have to do to create an extension that would make ParseOptions() return all command line arguments in lower case?
I would like to be able to use the extension as follows:
var argArray = ParseOptions().MyExtToLower();
Note: I'm asking this to better understand how to create an extension for a method. I'm not actually interested in getting lower case command line arguments this way.
public static string[] MyExtToLower(this string[] source)
{
for (int i = 0; i < source.Length; i++)
{
source[i] = source[i].ToLower();
}
return source;
}
Notice the this keyword in the parameter list. That is what makes it possible to call the method like this:
var argArray = ParseOptions().MyExtToLower();
To be clear, you're not actually adding an extension to a method here. What you are doing is adding an extension to the type that the method returns.
You seem to be talking about Fluent Interfaces. Look at this example - http://blog.raffaeu.com/archive/2010/06/26/how-to-write-fluent-interface-with-c-and-lambda.aspx
Or, you can create extension methods on the type you are returning ( in your case, string[] ) to get the method chaining - http://msdn.microsoft.com/en-us/library/bb383977.aspx
For the syntax you describe you would have to extend String[] or possibly IEnumerable<String> the following way:
public static class MyExtensions {
public static String[] MyExtToLower(this String[] strings) {
return strings.Select(s => s.toLower()).ToArray();
}
public static IEnumerable<String> MyExtToLower(this IEnumerable<String> strings) {
return strings.Select(s => s.toLower());
}
}
You don't create extension of methods, you create methods which extend objects' capabilities. Those methods must be static and part of a static class. They must have one parameter marked with the this keyword to indicate which object you want to extend. In your case, you must write something like:
// the class must be static, I usually declare a class reserved for extension method.
// I mark it as partial so that I can put every method in the same file where I use it.
public static partial class Extension {
// This is the extension method; it must be static. Note the 'this' keyword before
// the first parameter: it tells the compiler extends the string[] type.
public static MyExtToLower( this string[ ] args ) {
// your code
}
}
Note that you cannot override instance method. Altough you can have a method with the same signature as an instance method that method will be never called due to the way the compiler binds to.
When i run the following code :
var aList = new List<string>{"a", "b", "c"};
dynamic a = aList.Where(item => item.StartsWith("a"));
dynamic b = a.Count();
Microsoft.CSharp.RuntimeBinder.RunTimeBinderException raises.
But when I write a code snippet like this:
public interface IInterface
{
}
public class InterfaceImplementor:IInterface
{
public int ID = 10;
public static IInterface Execute()
{
return new InterfaceImplementor();
}
}
public class MyClass
{
public static void Main()
{
dynamic x = InterfaceImplementor.Execute();
Console.WriteLine(x.ID);
}
}
it's work.
Why first code snippet doesn't work?
Because the Count method is an extension method on IEnumerable<T> (Once you call Where, you don't have a list anymore, but an IEnumerable<T>). Extension methods don't work with dynamic types (at least in C#4.0).
Dynamic lookup will not be able to find extension methods. Whether extension methods apply or not depends on the static context of the call (i.e. which using clauses occur), and this context information is not currently kept as part of the payload.
Will the dynamic keyword in C#4 support extension methods?
Extension methods are syntactic sugar that allow you to call a static method as if it was a real method. The compiler uses imported namespaces to resolve the correct extension method and that is information the runtime doesn't have. You can still use the extension methods, you just have to call them directly in their static method form like below.
var aList = new List<string>{"a", "b", "c"};
dynamic a = aList.Where(item => item.StartsWith("a"));
dynamic b = Enumerable.Count(a);
In c# it's possible to create a list of functions like so:
var myList = new List< Func<Foo> >();
This will allow functions (delegates) that take no arguments and return a value of type Foo to be added to the list. So something like:
Foo myFunc1() { ... }
would be a valid member of that list. My question is, how do I declare the type for a templatized function? How can I construct a List<> that will hold functions of the form:
T myFunc2<T>() { ... }
You need to do that inside a templatized class or method. Then you can refer to the generic type T just as you would refer to the specific type Foo.
In other words:
public class FuncContainer<T>
{
private List<Func<T>> list = new List<Func<T>>();
public void Fill()
{
// Initialize list
}
}
I think the other answers so far have misunderstood the problem... and I don't think you can actually do it, if I've read it correctly. Am I right in saying you'd like to be able to write this:
List<???> list = new List<???>(); // This line won't work
list.Add(Method1);
list.Add(Method2);
...
static int Method1() { ... }
static string Method2() { ... }
If I've misunderstood, and a simple generic type parameter of T in your method or class suffices, I'll delete this answer :)
The closest you could come to the above would be something like this:
public class FuncList
{
private readonly List<Delegate> list = new List<Delegate>();
public void Add<T>(Func<T> func)
{
list.Add(func);
}
}
You'd then use it as:
FuncList list = new FuncList();
list.Add<int>(Method1);
list.Add<string>(Method2);
Quite what you'd do with the list afterwards is tricky... what did you have in mind?
Yes this first signature is completely valid.
The signature of the last function you suggested is the following
List<Func<T>> x;
This holds a list of delegates which take no arguments and produce a T value.
I've got a base class:
public abstract class StuffBase
{
public abstract void DoSomething();
}
And two derived classes
public class Stuff1 : StuffBase
{
public void DoSomething()
{
Console.WriteLine("Stuff 1 did something cool!");
}
public Stuff1()
{
Console.WriteLine("New stuff 1 reporting for duty!");
}
}
public class Stuff2 : StuffBase
{
public void DoSomething()
{
Console.WriteLine("Stuff 2 did something cool!");
}
public Stuff1()
{
Console.WriteLine("New stuff 2 reporting for duty!");
}
}
Okay, now say I've got a list of items:
var items = new List<StuffBase>();
items.Add(new Stuff1());
items.Add(new Stuff2());
and I want them all to call their DoSomething() method. I could expect to just iterate the list and call their DoSomething() method, so let's say I've got a method to do that called AllDoSomething() that just iterates over the list and does the job:
public static void AllDoSomething(List<StuffBase> items)
{
items.ForEach(i => i.DoSomething());
}
What is the practical difference of the following method?
public static void AllDoSomething<T>(List<T> items) where T: StuffBase
{
items.ForEach(i => i.DoSomething());
}
Both methods appear in real terms, although being syntactically different, to be doing the same thing.
Are they just different ways of doing the same thing? I understand generics and type constraints but can't see why I would use one way over the other in this instance.
This is because as of yet, C# does not support Covariance.
More formally, in C# v2.0 if T is a
subtype of U, then T[] is a subtype of
U[], but G is not a subtype of G
(where G is any generic type). In
type-theory terminology, we describe
this behavior by saying that C# array
types are “covariant” and generic
types are “invariant”.
Reference: http://blogs.msdn.com/rmbyers/archive/2005/02/16/375079.aspx
If you have the following method :
public static void AllDoSomething(List<StuffBase> items)
{
items.ForEach(i => i.DoSomething());
}
var items = new List<Stuff2>();
x.AllDoSomething(items); //Does not compile
Where as if you use the generic type constraint, it will.
For more information about Covariance and Contravariance], check out Eric Lippert's series of posts.
Other posts worth reading :
http://www.pabich.eu/blog/archive/2008/02/12/c-generics---parameter-variance-its-constraints-and-how-it.aspx
http://blogs.msdn.com/rmbyers/archive/2006/06/01/613690.aspx
http://msdn.microsoft.com/en-us/library/ms228359(VS.80).aspx
http://www.csharp411.com/convert-between-generic-ienumerablet/
http://research.microsoft.com/apps/pubs/default.aspx?id=64042
Why can't List<parent> = List<child>?
Suppose you had a list:
List<Stuff1> l = // get from somewhere
Now try:
AllDoSomething(l);
With the generic version, it will be allowed. With the non-generic, it won't. That's the essential difference. A list of Stuff1 is not a list of StuffBase. But in the generic case, you don't require it to be exactly a list of StuffBase, so it's more flexible.
You could work around that by first copying your list of Stuff1 into a list of StuffBase, to make it compatible with the non-generic version. But then suppose you had a method:
List<T> TransformList<T>(List<T> input) where T : StuffBase
{
List<T> output = new List<T>();
foreach (T item in input)
{
// examine item and decide whether to discard it,
// make new items, whatever
}
return output;
}
Without generics, you could accept a list of StuffBase, but you would then have to return a list of StuffBase. The caller would have to use casts if they knew that the items were really of a derived type. So generics allow you to preserve the actual type of an argument and channel it through the method to the return type.
In the example you provided there is no difference but try the following:
List<Stuff1> items = new List<Stuff1>();
items.Add(new Stuff1());
AllDoSomething(items);
AllDoSomething<StuffBase>(items);
The first call works well but the second one does not compile because of generic covariance