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);
Related
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();
After saving an anonymous type into a variable of type "IEnumerable" using LINQ, I discovered that it is possible to use several methods that were defined inside of the class "Enumerable" over the aforementioned variable. How is this possible? It should also be noted that "IEnumerable" is an interface.
Here is a small code example:
class MyClass
{
public string Name;
}
class Program
{
static void Main(string[] args)
{
MyClass[] myArray =
{
new MyClass{Name = "Bill"},
new MyClass{Name = "Bill"},
new MyClass{Name = "Steve"}
};
IEnumerable<MyClass> variable = from myInstance in myArray
where myInstance.Name == "Bill"
select myInstance;
MyClass[] newArray = variable.ToArray<MyClass>(); // How is it possible for me to use "ToArray<T>()" on "varialble"?
}
}
This uses a C# feature called extension methods. The method is defined in a separate class (hence the name - it extends the functionality of the original class/interface). The first parameter is prefixed by the this keyword, and the method can be called as if it's a method on that parameter (i.e. on your IEnumerable<MyClass>).
In your example, you are using a library called LINQ, which is composed entirely of extension methods. You can see the source code for ToArray on github. Your code will have using System.Linq; at the top, which is what allows you to call the method in your code.
I have an extension method
public static class DbMigratorExtensions
{
public static IEnumerable<string> DoCoolStuff(this DbMigrator dbMigrator, string[] first, string[] second)
{
// ...
}
}
and I'm trying to use it like
DbMigrator.DoCoolStuff
but I get the
'DbMigrator' does not contain a definition for ...
I have followed all the bullet points on
Why is my Extension Method not showing up in my test class?
Also I will note that VS recognizes
DbMigratorExtensions.DoCoolStuff
so I'm not sure why it isn't working as an extension method.
Extension methods work on object instances, not types.
So you need to change
DbMigrator.DoCoolStuff(...);
to
var migrator = new DbMigrator();
var stringList = migrator.DoCoolStuff(...);
If DoCoolStuff() doesn't need an instance, it should not be an extension method.
If what you want is a static extension method, C# does not currently support this. You can only make non-static extension methods. This will probably change at some point.
I'm wondering if the following can be refactored in the way I would like it:
[EditorBrowsable(EditorBrowsableState.Never)]
public static class ListExtensions
{
public static PaginatedList<Y> ToMappedPaginatedList<T, Y>(this PaginatedList<T> source)
{
var mappedList = new List<Y>();
Mapper.Map(source, mappedList);
return new PaginatedList<Y>(mappedList, source.PageIndex, source.PageSize, source.TotalCount);
}
}
The Mapper.Map line is using AutoMapper to map properties from an entity to a DTO object.
This is called like this:
var list = await _service.GetAllAsync(pageIndex, _pageSize);
var dtoList = list.ToMappedPaginatedList<Farmer, FarmerDTO>();
but I'd like to call it like this:
var dtoList = list.ToMappedPaginatedList<FarmerDTO>();
This saves a little bit of typing and you don't always need to be aware of the source list its type. Unfortunately this code doesn't work and I'm not sure if there's a simple answer.
Anyone got an idea?
Thanks in advance.
Yannick
If you have access to the PaginatedList class, putting the method in there will enable the syntax you desire since the instance knows what it's own type is.
I don't recommend the following but it demonstrates a way to take advantage of type inference.
You can enable type inference by adding a 2nd "useless" parameter of type Y.
If you pass default(FarmerDTO) as the 2nd parameter, a null will be passed as the parameter value but the intended type will be inferred.
[EditorBrowsable(EditorBrowsableState.Never)]
public static class ListExtensions
{
public static PaginatedList<Y> ToMappedPaginatedList<T, Y>(this PaginatedList<T> source, Y destinationPlaceholder)
{
var mappedList = new List<Y>();
Mapper.Map(source, mappedList);
return new PaginatedList<Y>(mappedList, source.PageIndex, source.PageSize, source.TotalCount);
}
}
Call it like this:
var result1 = s.ToMappedPaginatedList(default(FarmerDTO));
Fair warning. I've never used this because I find the resulting code to be non-obvious as to what it is doing.
Either you call a method and specify all the generic arguments or you specify none and let the compiler infer them, there's no support for partial inference.
As such, the only way to get your code to compile is to make ToMappedPaginatedList take 1 generic parameter, instead of two.
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.