C# Generic Extension Method Compiles But Unusable? - c#

I am trying to write a generic extension method for adding a fixed matrix to an "elastic" matrix. The extension method compiles and (I assume) its code works fine in a regular method. Knowing I'll be using this function a lot for various types, I would much prefer to figure this problem out instead of limping along with a band-aid:
public void AddMatrix<T>(this List<T[]> MyList, T[,] Matrix)
{
if (MyList == null) throw new ArgumentNullException("MyList");
if (Matrix == null) throw new ArgumentNullException("Matrix");
for (int i = 0; i < Matrix.GetLength(0); i++)
{
T[] aLine = new T[Matrix.GetLength(1)];
for (int j = 0; j < Matrix.GetLength(1); j++)
aLine[j] = Matrix[i, j];
MyList.Add(aLine);
}
}
public void testAddMatrix()
{
List<string[]> aMyBigMatrix = new List<string[]>();
string[,] aSmallerMatrix =
{
{
"foo",
"bar",
"what"
}
};
aMyBigMatrix.AddMatrix(aSmallerMatrix); // .AddMatrix is not showing up here in Intellisense?
}

From MSDN:
To defining and call the extension method
Define a static class to contain the extension method. The class must be visible to client code.
Implement the extension method as a static method with at least the same visibility as the containing class.
The first parameter of the method specifies the type that the method operates on; it must be preceded with the this modifier.
Your method is not static (2.).

You are writing an extension method, AddMatrix<T> needs to be static.

Extension methods have to be static.

Extension methods must be static.
Change it to:
public static void AddMatrix(this List MyList, T[,] Matrix)
And make sure the class is static too.

As everyone is quick to point out, extension methods must be static.
When I attempted to duplicate your error, I got a compiler error "Extension method must be static", so it seems strange to me that you report that your code compiles. When you try to compile it, look at the Error List to see if it is in fact empty. I suspect you will find an error message that you had not noticed before. If you are able to see the compiler errors, your mistakes of this nature will be easy to identify and fix.

Related

Update PointF Value Using Extension Method in C# [duplicate]

I want to be able to write extension methods so that I can say:
lines.ForceSpaceGroupsToBeTabs();
instead of:
lines = lines.ForceSpaceGroupsToBeTabs();
However, the following code currently outputs:
....one
........two
instead of:
Tone
TTtwo
What do I have to change in the following code to make it output:
Tone
TTtwo
(note that for visibility, . = space, T = \t):
using System;
using System.Collections.Generic;
namespace TestExtended82343
{
class Program
{
static void Main(string[] args)
{
List<string> lines = new List<string>();
lines.Add("....one");
lines.Add("........two");
lines.ForceSpaceGroupsToBeTabs();
lines.ForEach(l => Console.WriteLine(l));
Console.ReadLine();
}
}
public static class Helpers
{
public static void ForceSpaceGroupsToBeTabs(this List<string> originalLines)
{
string spaceGroup = new String('.', 4);
List<string> lines = new List<string>();
foreach (var originalLine in originalLines)
{
lines.Add(originalLine.Replace(spaceGroup, "T"));
}
originalLines = lines;
}
}
}
You have to modify the contents of the List<string> passed to the extension method, not the variable that holds the reference to the list:
public static void ForceSpaceGroupsToBeTabs(this List<string> lines)
{
string spaceGroup = new String('.', 4);
for (int i = 0; i < lines.Count; i++)
{
lines[i] = lines[i].Replace(spaceGroup, "T");
}
}
You'd have to change the contents of the original list - just reassigning the parameter to have a different value isn't going to do it. Something like this:
public static void ForceSpaceGroupsToBeTabs(this List<string> lines)
{
string spaceGroup = new String('.', 4);
for (int i = 0; i < lines.Count; i++)
{
lines[i] = lines[i].Replace(spaceGroup, "T");
}
}
It's worth noting that this has nothing to do with extension methods. Imagine you'd just called:
Helpers.ForceSpaceGroupsToBeTabs(lines);
... because that's what the code is effectively translated into. There's nothing special about the fact that it's an extension method; if you change the code so that the "normal" static method will work, then it'll work as an extension method too. As noted in the comments, one thing you can't do with an extension method is make the first parameter a ref parameter.
(EDIT: I realise this is the exact same code that dtb posted, although we arrived there independently. I'm keeping this answer anyway, as it's got more than code.)
If it's a reference type, you'd have to change it's contents. If it's a value type you're passing in, you're out of luck. The very existence of extension methods is put into place to support functional paradigms in C#, and those functional paradigms, by their very essence, tend towards immutability of types, hence the inability to change the value off of which the extension method is called.
In other words, while you could do it, it may not be in keeping with the "spirit" of functional programming.

What causes this list to be passed by reference when called one way, but by value another?

I was making a simple test for running a validation method and came across this strange situation.
public IEnumerable<int> ints (List<int> l)
{
if(false)yield return 6;
l.Add(4);
}
void Main()
{
var a = new List<int>();
var b = new List<int>();
for( int i = 0; i < 4; i++ ){
a.Add(i);
b.Add(i);
}
a.AddRange(ints(a));
ints(b);
Console.WriteLine(a);
Console.WriteLine(b);
}
Once this code runs, a will contain [0,1,2,3,4]. However, b will contain [0,1,2,3]. Why did calling the method as an argument in AddRange allow the list to be passed by reference? Or if that didn't happen, what did?
ints(b) call does not enumerate IEnumerable, so code never reaches l.Add(4) line, unlike in AddRange case which enumerates all items to add them to the list.
To see it called for b case enumerate result manually:
ints(b).ToList();
IEnumerable<T> implemented via functions are not executing body of the function before enumeration starts - the code is actually transformed by compiler into class with states to support true lazy evaluation of enumerable (details can be found in multiple articles, i.e. Iterator Pattern demystified - link provided by Tim Schmelter).

Overwriting an extension method C#

I am using RestSharp to create http requests to a webservice. One of the parameters length is very long running >100 K characters, so I figured I'll need to use the POST method (because of limitations on length of query string with GET). However, when I tried doing so I got an exception that the uri is too long. I downloaded their source code to find out why. Take a look at the following code:
querystring.AppendFormat("{0}={1}", p.Name.UrlEncode(), p.Value.UrlEncode());
Now the UrlEncode() method is an extension method available in StringExtensions.cs class and it's implementations is like so:
public static string UrlEncode(this string input)
{
return Uri.EscapeDataString(input);
}
The problem is that Uri.EscapeDataString cannot process a string more than 65519 characters (see post - Uri.EscapeDataString() - Invalid URI: The Uri string is too long)
My problem can be solved if the UrlEncode extension method was implemented like this
public static string UrlEncode(this string input)
{
int limit = 65520;
StringBuilder sb = new StringBuilder();
int loops = input.Length / limit;
for (int i = 0; i <= loops; i++)
{
if (i < loops)
{
sb.Append(Uri.EscapeDataString(input.Substring(limit * i, limit)));
}
else
{
sb.Append(Uri.EscapeDataString(input.Substring(limit * i)));
}
}
return sb.ToString();
}
The issue is that I DON'T want to HAVE to modify the source code. Is there a way I can write my own extension method in MY source code such that when the third party code is trying to invoke UrlEncode() it ignores it's own extension method and instead calls my extension method??
Any help is much appreciated. Thanks.
Thankfully, there's no way that I know of. The extension method s.UrlEncode() is basically syntactic sugar for
StringExtensions.UrlEncode(s);
Since this method is static, there's no way to "override" it. In addition, it's bound to that method at compile time, so there's no way to redirect it to a different method at run time.
It should NOT be allowed, either. If it were, You could create an "override" it to format your C drive!.
If YOU want to use a different version, you could create a new extension method with a different name, or figure out a way to shorten your parameter lengths. :)
one solution would be to extend the existing Uri class with hiding through inheritance - you should inherit the existing Uri class and then override with the new operator the desired method. This way you will change the default behaviour without modifying original code. Code example:
public class A
{
public int Get1()
{
return 1;
}
public int Get2()
{
return 100;
}
}
public class B : A
{
// override A's Get1
public new int Get1()
{
return 2;
}
}
and the output of the call:
var b = new B();
System.Console.WriteLine(string.Format("{0} - {1}", b.Get1(), b.Get2()));
would be:
2 - 100
and not 1 - 100!
Hope this helps.
Regards,
P.
Check out this answer to see how to do a POST using RestSharp. The payload goes in the message body, not in the query string.

What is the lifetime of a delegate created by a lambda in C#?

Lambdas are nice, as they offer brevity and locality and an extra form of encapsulation. Instead of having to write functions which are only used once you can use a lambda.
While wondering how they worked, I intuitively figured they are probably only created once. This inspired me to create a solution which allows to restrict the scope of a class member beyond private to one particular scope by using the lambda as an identifier of the scope it was created in.
This implementation works, although perhaps overkill (still researching it), proving my assumption to be correct.
A smaller example:
class SomeClass
{
public void Bleh()
{
Action action = () => {};
}
public void CallBleh()
{
Bleh(); // `action` == {Method = {Void <SomeClass>b__0()}}
Bleh(); // `action` still == {Method = {Void <SomeClass>b__0()}}
}
}
Would the lambda ever return a new instance, or is it guaranteed to always be the same?
It's not guaranteed either way.
From what I remember of the current MS implementation:
A lambda expression which doesn't capture any variables is cached statically
A lambda expression which only captures "this" could be captured on a per-instance basis, but isn't
A lambda expression which captures a local variable can't be cached
Two lambda expressions which have the exact same program text aren't aliased; in some cases they could be, but working out the situations in which they can be would be very complicated
EDIT: As Eric points out in the comments, you also need to consider type arguments being captured for generic methods.
EDIT: The relevant text of the C# 4 spec is in section 6.5.1:
Conversions of semantically identical anonymous functions with the same (possibly empty) set of captured outer variable instances to the same delegate types are permitted (but not required) to return the same delegate instance. The term semantically identical is used here to mean that execution of the anonymous functions will, in all cases, produce the same effects given the same arguments.
Based on your question here and your comment to Jon's answer I think you are confusing multiple things. To make sure it is clear:
The method that backs the delegate for a given lambda is always the same.
The method that backs the delegate for "the same" lambda that appears lexically twice is permitted to be the same, but in practice is not the same in our implementation.
The delegate instance that is created for a given lambda might or might not always be the same, depending on how smart the compiler is about caching it.
So if you have something like:
for(i = 0; i < 10; ++i)
M( ()=>{} )
then every time M is called, you get the same instance of the delegate because the compiler is smart and generates
static void MyAction() {}
static Action DelegateCache = null;
...
for(i = 0; i < 10; ++i)
{
if (C.DelegateCache == null) C.DelegateCache = new Action ( C.MyAction )
M(C.DelegateCache);
}
If you have
for(i = 0; i < 10; ++i)
M( ()=>{this.Bar();} )
then the compiler generates
void MyAction() { this.Bar(); }
...
for(i = 0; i < 10; ++i)
{
M(new Action(this.MyAction));
}
You get a new delegate every time, with the same method.
The compiler is permitted to (but in fact does not at this time) generate
void MyAction() { this.Bar(); }
Action DelegateCache = null;
...
for(i = 0; i < 10; ++i)
{
if (this.DelegateCache == null) this.DelegateCache = new Action ( this.MyAction )
M(this.DelegateCache);
}
In that case you would always get the same delegate instance if possible, and every delegate would be backed by the same method.
If you have
Action a1 = ()=>{};
Action a2 = ()=>{};
Then in practice the compiler generates this as
static void MyAction1() {}
static void MyAction2() {}
static Action ActionCache1 = null;
static Action ActionCache2 = null;
...
if (ActionCache1 == null) ActionCache1 = new Action(MyAction1);
Action a1 = ActionCache1;
if (ActionCache2 == null) ActionCache2 = new Action(MyAction2);
Action a2 = ActionCache2;
However the compiler is permitted to detect that the two lambdas are identical and generate
static void MyAction1() {}
static Action ActionCache1 = null;
...
if (ActionCache1 == null) ActionCache1 = new Action(MyAction1);
Action a1 = ActionCache1;
Action a2 = ActionCache1;
Is that now clear?
No guarantees.
A quick demo:
Action GetAction()
{
return () => Console.WriteLine("foo");
}
Call this twice, do a ReferenceEquals(a,b), and you'll get true
Action GetAction()
{
var foo = "foo";
return () => Console.WriteLine(foo);
}
Call this twice, do a ReferenceEquals(a,b), and you'll get false
I see Skeet jumped in while I was answering, so I won't belabor that point. One thing I would suggest, to better understand how you are using things, is to get familiar with reverse engineering tools and IL. Take the code sample(s) in question and reverse engineer to IL. It will give you a great amount of information on how the code is working.
Good question. I don't have an "academic answer," more of a practical answer: I could see a compiler optimizing the binary to use the same instance, but I wouldn't ever write code that assumes it's "guaranteed" to be the same instance.
I upvoted you at least, so hopefully someone can give you the academic answer you're looking for.

Invalid token 'while' in class, struct, or interface member declaration in very simple code

I am not sure what the problem is but I keep receiving this error when I try to use a while statement in my code.
Invalid token 'while' in class,
struct, or interface member
declaration
I want to use a while loop to have something continuously update while a statement is true.
The rest of my code is rather long but whenever I type in the syntax:
while(a<b)
{
//do whatever i want it to do here
}
It gives me that compiler error right off the bat. Not quite sure what the problem is. I am doing this in a C# windows application under the Form1.cs file with all the other event handlers (for buttons and such).
Thanks!
I was unaware that loops had to be placed within a method (fairly new to c#), but I tried it and no errors were returned. Thanks for your help everybody!
Previously, I just had the loop within the main class of the program.
Based on the error, it sounds like the compiler thinks this code is typed directly in the body of a class/struct/interface declaration. Statements while/if/for/etc ... must appear with in a method.
Try moving this code into a method to fix the problem. If it's in a method, you likely have a mismatched brace problem.
There's nothing wrong with the while, it's something above it that's the problem.
Check for mismatched braces and semicolons in a comment or something like that.
C# is not allowed to write code directly into the classes; it is allowed to write only data members and function members directly into the classes.
You can also get this if you have punctuation issues, I got it today when I missing a simple parentheses:
public static string GetPasswordForEnvironment)
should have been:
public static string GetPasswordForEnvironment()
But the error showed up on the first "if" statement later in the function.
C# does not provide writing the for, while or foreach kind of looping statement directly inside the class. These statements should be within a user defined method, main method or constructors.
class Array
{
public static void main(string[] args)
{
int[] n = new int[10]; /* n is an array of 10 integers */
/* initialize elements of array n */
for (int i = 0; i < 10; i++)
{
n[i] = i + 100;
}
/* output each array element's value */
foreach (int j in n)
{
int i = j - 100;
Console.WriteLine("Element[{0}] = {1}", i, j);
}
}
}

Categories

Resources