I have found several links to methods of making extension methods work in .NET2.0 (The moth, Discord & Rhyme, Stack Overflow). I have also heard vaguely from a colleague that this causes some problems with libraries or something? Is this the case? Also all 3 use different methods:
The moth:
namespace System.Runtime.CompilerServices
{
public class ExtensionAttribute : Attribute { }
}
Discord and Rhyme
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class ExtensionAttribute : Attribute {}
}
Stack Overflow
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class
| AttributeTargets.Method)]
public sealed class ExtensionAttribute : Attribute {}
}
Whats the difference between these methods, and which one would you recommend?
Ultimately it isn't going to make much difference; you could argue that the one that matches the runtime is preferred, but the ideal answer is to switch to .NET 3.5 (otherwise at a later date it can get confusing with different versions of the same attribute in scope etc).
The [AttributeUsage] will prevent it being attached to things where it won't do anything - but it won't do aything by itself anyway...
Looking at metadata against the type, the exact attribute usage seems most like the stackoverflow variant - but ultimately this isn't hugely important - the name and namespace is all that matters (and that it inherits from Attribute).
The difference is simple enough:
In your first example, you can put the attribute anywhere. In the second example, you can only apply it to a method, never more than one to the same method and an inherited class with the method overridden will not inherit the attribute. In the third example, you can apply it to a method, a class or an assembly.
If you try to apply it in any other place, you will get a compiler error.
The second seems to make most sense.
I would recommend Discord and Rhyme because it providing meaningful constraints for how the attribute is supposed to be applied.
It can only be applied to methods
You can only apply it once
The attribute cannot be inherited
Personally, I would recommend avoiding all three. Each option makes this work by performing a "trick" - I would not rely on this for production code.
If you want to use extension methods, upgrade to C# 3.0. Otherwise, just stick to calling the method using the non-extension method syntax.
You can always take an extension method call like so:
public static class Utility {
public static string Extension(this string original) { ... }
// call with:
var newString = myString.Extension();
And call it directly:
string newString = Utility.Extension(myString);
This will be more consistent with C#/.NET 2 syntax, and would be my recommendation.
The SO version is the accurate one, for the pure sake of accuracy you should use it.
Fwiw, the AttributeTarget.Method specifier is crystal clear. Class and Assembly less so. Both the C# and the VB.NET compiler emit the attribute on the static class / Module that contains the extension method. And on the assembly that contains the class / Module. Why they do this is less crystal clear, it wouldn't be needed to properly compile them. I'm guessing this is an optimization at work, helping both the compiler and IntelliSense discover when an extension method should be considered.
Getting the attribute applied to the assembly is actually a problem. That won't work right when you compile code to .netmodules. But that's a very obscure issue.
Related
Say I have these files:
MyCode.cs
namespace MyCodeNamespace
{
public class MyClass
{
//OMITTED
}
internal static class MyExtensions
{
internal static void Foo(this string str)
{
//OMITTED
}
}
}
OtherCode.cs
using MyCodeNamespace;
namespace OtherCodeNamespace
{
//OMITTED
}
The two files are part of the same assembly. Is there any way I can make Foo accessible to MyCode.cs but not to OtherCode.cs? My question is similar to this question:
C# Extension Methods only visible and accessible within one class ("private")
But its accepted answer isn't really what I'm looking for. I want to make an extension method that's only visible to the code I'm working on, and according to the answer to the above question, someone could still access it by adding a "using" statement. Is there a way I can create an extension method that is only visible to my code, and nowhere else, not even by another class in the same assembly?
I ask because the syntax for calling an extension method is handy and would be useful for what I'm working on (otherwise I'd just create a private method instead), but I don't want others to see it and use it from their code in case it doesn't do what they assume it does. And thanks to Visual Studio's intellisense, my extension methods are currently showing up in the list of available methods (along with the option to add the namespace they're in).
There is no such thing as a namespace-limited access modifier in the .NET platform. From the docs
public : Access is not restricted.
protected : Access is limited to the containing class or types derived from the containing class.
Internal : Access is limited to the current assembly.
protected internal: Access is limited to the current assembly or types derived from the containing class.
private : Access is limited to the containing type.
That's all you have to work with. So the answer is no.
Extension methods are just semantic sugar that compile to the same IL as calling the static helpers directly.
MyExtensionMethods.DoSomething(myObject);
myObject.DoSomething();
You cannot restrict it from being called, but you can remove its visibility from Intellisense.
Simply move your extension methods to a different namespace, add a using statement in your MyCode.cs and don't include that namespace in OtherCode.cs
[update]
If you really need to restrict the caller, you could try using reflection to determine and restrict, but this is a bit overkill. Best to simply use a private static helper instead of doing this.
var frame = new System.Diagnostics.StackFrame(1, false);
var method = frame.GetMethod();
var type = method.DeclaringType;
// allow|deny type
I had a similar problem. I did not want the programmer to see my inner extension methods when configuring services in ASP.NET Core.
The solution for me was to add all extension methods to namespace Microsoft.Extensions.DependencyInjection that is used in Startup.cs and the user can see those methods. (As you would always do.)
If I wanted to "hide" something I added the extension method to MyNamespace.Extensions. If the user writes the correct name the helper for add using will show up but by default it won't be listed.
I know this is not a solution but might help someone.
think about similar thing;
c# assembly, friend assembly
will try InternalsVisibleTo;
if your classes is closed maybe will not helpfull but you can try it;
Coming from C++ background myself, it takes some time to get used to C#. In C#, one uses the dot operator (.) more often than the ::-operator (the namespace qualifier operator in C#), to access namespace and class scopes.
In C++, one uses the dot operator (.) to access members of an instance of a class. Scope resolution operator (::) on the other hand, is used to access members of a class without an instance of that class. To me, this makes sense and is both logical and consistent.
While I can accept different approach used in C#, there seems to be at least one instance, in which I see an inconsistence. At least, that is how it appears to me. It has to do with the global keyword:
global::System.Console.WriteLine("Hello World");
Could somebody explain to me why namespace alias qualifier is required to use with global keyword instead of the dot operator?
It's not really common but there are some situations when it's handy.
Imagine you have this a class System inside current namespace:
namespace Test {
static class System {
public static Do() { }
}
class Foo {
void foo() {
System.Do(); // What's this?
}
}
}
Do you want to make it more complicate? Add an inner class in System and call it, for example, Action. Of course these are edge cases and probably you won't ever need to use global:: but language itself has to handle this situation. See MSDN for more examples.
Global namespace aliases are also useful in another situation: when you reference two DLLs and they have the same namespaces and classes (for example because they simply are the two versions of same stuff). In that case how can you reference them? Same problem described here for C++. You can change namespace to include version number but it's a pain each time you change it (and VS automatic refactoring AFAIK doesn't work with namespaces) or you can reference them using two aliases. They'll be accessed, for example, like this:
Version1::CompanyName.MyNamespace.MyClass
Version2::CompanyName.MyNamespace.MyClass
Also note that it's a good practice (to include global:: namespace) when you're generating code (for example all designers generated code) because you don't know in which scenario that code will be compiled (then collisions may occur).
Reasoning about :: and . well...it's not a question for SO (unless you're so lucky Eric is having some fun here on SO) but I may guess it's because they're different things. If same operator . is used then how can parser understand with global.System you want to use global namespace alias and not a class or namespace named global? They had to make global a reserved keyword and it won't solve the other problem of conflicting hierarchies...
I found a class that looks something like:
using System;
// no using statement that brings either IMyClass or
// MyClassExtensions into scope
namespace Org.Foo {
class MyClass {
public void QuizzicalMethod(IMyClass thingy,
string stringToPass) {
thingy.ExtensionMethod(StringToPass);
}
}
There is an IMyClass interface definition in IMyClass.cs in the codebase (in the same namespace and directory), but it contains no definition for QuizzicalMethod. Instead, MyClassExtensions.cs has:
using System;
namespace Org.Foo {
public static class MyClassExtensions {
public static void ExtensionMethod (this IMyClass self,
string stringToPass) {
// Do some stuff
}
}
}
Thus, MyClassExtensions is clearly out of scope when MyClass is defined, and thus when QuizzicalMethod--which uses IMyClassExtensions.ExtensionMethod--is defined. It seems to me like both the parameter list of the QuizzicalMethod definition and its call of thingy.ExtensionMethod ought to break. (Makes me wonder if there's a code coverage issue in the tests.) This leads to some questions:
How does this compile without an error?
Why would a class author even want to bring QuizzicalMethod out of the class definition and put it into an extension?
Does this fit an existing named pattern?
Is there some kind of scoping exception or late-binding going on? If so, how does it not break everything else in C#?
Thanks in advance!
EDIT: Fixed some typos.
Thus, MyClassExtensions is clearly out of scope when MyClass is defined
Nope, both MyClassExtensions and MyClass are declared in the same namespace. You don't need a using directive to invoke an extension method in the same namespace or an enclosing namespace.
You haven't explained where IMyClass is declared, so I can't comment on that.
From section 7.6.5.2 of the C# 5 specification (talking about finding a class C containing an extension method):
The search for C proceeds as follows:
Starting with the closest enclosing namespace declaration, continuing with each enclosing namespace declaration, and ending with the containing compilation unit, successive attempts are made to find a candidate set of extension methods:
If the given namespace or compilation unit directly contains non-generic type declarations Ci with eligible extension methods Mj, then the set of those extension methods is the candidate set.
If namespaces imported by using namespace directives in the given namespace or compilation unit directly contain non-generic type declarations Ci with eligible extension methods Mj, then the set of those extension methods is the candidate set.
Basically, this is just an extension method. Without knowing more of the real context, we can't comment on why this is an extension method rather than a method on IMyClass.
How does this compile without an error?
This compiles because the two classes are in the same namespace.
Why would a class author even want to bring QuizzicalMethod out of the class definition and put it into an extension?
It could have been done for backward compatibility: the author may wanted to publish this method as an extension when the class was already in production, without an ability to recompile classes that rely on MyClass.QuizzicalMethod.
It may have been done the other way around: it is the designer of MyClass who wanted to bring in the extension method into his class - for example, to make it easier for himself to access the method through reflection as an instance method (although it is certainly not a requirement - one can call an extension through reflection by calling a static method of the extension class).
Does this fit an existing named pattern?
Not as far as I know
Is there some kind of scoping exception or late-binding going on? If so, how does it not break everything else in C#?
Nothing special is going on here: two classes in the same namespace can see each other methods.
We are currently discussing whether Extension methods in .NET are bad or not. Or under what circumstances Extension methods can introduce hard to find bugs or in any other way behave unexpectedly.
We came up with:
Writing an extension method for types that are not under your control (e.g. extending DirectoryInfo with GetTotalSize(), etc...) is bad, because the owner of the API could introduce a method that hides our extension - and might have different edge cases. For example testing for null in an extension method will automatically translate into a NullReferenceException if the extension method is no longer used due to hiding.
Question:
Are there any other dangerous situations than "hiding" that we are not thinking of?
Edit:
Another very dangerous situation.
Suppose you have an extension method:
namespace Example.ExtensionMethods
{
public static class Extension
{
public static int Conflict(this TestMe obj)
{
return -1;
}
}
}
And use it:
namespace Example.ExtensionMethods.Conflict.Test
{
[TestFixture]
public class ConflictExtensionTest
{
[Test]
public void ConflictTest()
{
TestMe me = new TestMe();
int result = me.Conflict();
Assert.That(result, Is.EqualTo(-1));
}
}
}
Notice that the namespace where you use it is longer.
Now you reference a dll with this:
namespace Example.ExtensionMethods.Conflict
{
public static class ConflictExtension
{
public static int Conflict(this TestMe obj)
{
return 1;
}
}
}
And your Test will fail! It will compile without a compiler error. It will simply fail. Without you even having to specify "using Example.ExtensionMethods.Conflict". The compiler will walk the namespace name and find Example.ExtensionMethods.Conflict.ConflictExtension before Example.ExtensionMethods.Extension and will use that without ever complaining about ambiguous extension methods. Oh the horror!
Some curiosities:
extension methods might be called on null instances; this might be confusing (but sometimes useful)
the "hiding" issue is a biggie if they have different intent
equally, you might get a different extension method with the same name from 2 different namespaces; if you only have one of the two namespaces, this could lead to inconsistent behaviour (depending on which)...
...but if somebody adds a similar (same signature) extension method in a second namespace that your code uses, it will break at compile time (ambiguous)
(edit) And of course, there is the "Nullable<T>/new()" bomb (see here)...
I disagree, the whole point of extension methods is to add your members to black boxed classes. Like everything else there are pitfalls, you must be mindful in naming, implementation and understand the pecking order of the methods.
One breakage we've just found in the MoreLINQ project: if you write a generic extension method, it's impossible to make sure it will work with all types. We've got a method with this signature:
public static IEnumerable<T> Concat<T>(this T head, IEnumerable<T> tail)
You can't use that with:
"foo".Concat(new [] { "tail" });
because of the string.Concat method...
I've used Ruby on Rails for almost as long as I've used C#. Ruby allows you to do something similar to the new extension methods. There are, of course, potential problems if someone named the method the same, but the advantages of being able to add methods to a closed class far outweigh the potential dissadvantage (which would probably be caused by bad design or poor planning).
One thing you can do to make sure extension methods don't conflict with other methods (extension or otherwise) is to use FxCop with rules such as Prevent Duplicate Extension Method Signatures.
First of all I believe your wording is a bit misleading. I take it you're talking about "types" and not "objects".
Secondly, the big advantage of extension methods is that you can add features to type you don't control. If you control the type, why not just modify the type instead of relying on extension methods?
We took the attitude in my team that Extension Methods are so useful that you can't realistically ban them, but so dangerous (principally because of the hiding issue) that you have to be a bit cautious. So we decided that all Extension Method names have to be prefixed with X (so we have a bunch of XInit...() methods to initialise controls in useful ways, for instance). That way a) the likelihood of a naming collision is reduced and b) the programmer knows he is using an Extension Method and not a class method.
What .Net calls extension methods are also a limited form a MonkeyPatching (try to ignore the php rant in there).
That should give you some material for your discussion.
There's something I want to customize in the System.Web.Script.Services.ScriptHandlerFactory and other .NET stuff inside an internal class. Unfortunately, it's an internal class. What options do I have when trying to customize a method in this class?
You might find this recent article enlightening. Basically, it says that you can't override anything marked internal, and the source is about as authoritative as it gets. Best you can hope for is an extension method.
The internal keyword signifies that a unit of code (class, method, etc.) is "public" to the assembly it is in, but private to any other assembly.
Because you are not in the same assembly, you cannot do anything. If it wasn't internal you could use the new keyword on the method you're overriding (to hide the original implementation) when extending the class.
In short: you are to be SOL.
The only thing i can think of you could do is write a proxy class, where one of your private fields is the class you'd want to extend and you implement all it's methods and proxy their calls. that way you can still customize output, but you'd have to get your class used, and considering it's marked internal, i'm not sure that's possible without some serious hacking.
using System;
...
using System.Web.Script.Services
namespace MyGreatCompany.ScriptServices
{
public class MyScriptHandlerFactory /* implement all the interfaces */
{
private ScriptHandlerFactory internalFactory;
public MyScriptHandlerFactory()
{
internalFactory = new ScriptHandlerFactory();
}
...
}
}
This could make what you want to accomplish possible, but it won't be pretty.
I believe you can use Reflection to get around the access modifiers on a class, so perhaps you can use Reflection.Emit to generate a type that inherits from an internal type (but NOT the sealed modifier), though I can't find an example of this online.
This certainly works for accessing private members of classes, and probably for inheritance of non-sealed classes. But it doesn't help much if the target methods are not already marked virtual.
It depends on the assembly. This could possibly violate some licensing (although its similar to some sort of static linking), and maybe even make deployment a nightmare, but you could consider:
Decompile and copy the code over to your own project; modify as needed
Recompile/patch the assembly and add an "InternalsVisibleToAttribute"