Extension methods conflict - c#

Lets say I have 2 extension methods to string, in 2 different namespaces:
namespace test1
{
public static class MyExtensions
{
public static int TestMethod(this String str)
{
return 1;
}
}
}
namespace test2
{
public static class MyExtensions2
{
public static int TestMethod(this String str)
{
return 2;
}
}
}
These methods are just for example, they don't really do anything.
Now lets consider this piece of code:
using System;
using test1;
using test2;
namespace blah {
public static class Blah {
public Blah() {
string a = "test";
int i = a.TestMethod(); //Which one is chosen ?
}
}
}
The Question:
I know that only one of the extension methods will be chosen.
Which one will it be ? and why ?
Edit:
This also bothers me, but not as much because it's a static method in a static class after all:
How can I choose a certain method from a certain namespace ?
Usually I'd use Namespace.ClassNAME.Method() ... But that just beats the whole idea of extension methods. And I don't think you can use Variable.Namespace.Method()

No method will be chosen: the call is ambiguous and will not compile.
Why can't you do Namespace.ClassNAME.Method()? Certainly there is nothing that prevents you from treating extension methods as normal static methods, and in fact this is the only way for you to fix the ambiguity and have the program compile.

I had this exact question so I found this post two years later. However, I think it is important to note that this will only not compile and give the "The call is ambiguous" error if the code calling the duplicate extension methods is not in the same namespace as one of them.
If the OP were to change the namespace of his class Blah to either test1 or test2, then the code compiles, and the extension in the same namespace as the caller is used - even when both namespaces are represented in the usings. So if Blah is in the test1 namespace, "1" is returned, and if Blah is in the test2 namespace, "2" is returned.
I think this is important to add to the above answers, because I think one mainstream use-case is to have extensions in a local class library that references external extension libraries (e.g. devs share a common utility library, but have some local custom extensions that might unwittingly have the same name). By maintaining the custom local extensions in the same namespace as the code that uses them, you can maintain the extension call syntax and not have to revert to treating them as static method calls.

As Jon says, if both of these exist when you do the compilation, the compilation will just fail.
But if only one exists at the time of compilation and a external library later gets updated to add the second, the code you compiled will still continue to use the first one. This is because the compiler interally turns your code into the longhand form of calling namespace.classname.method.

I migrated big solution from .Net 4.7.1 to .Net 4.7.2. We use LINQ in our code, and we use well known and established library with name MoreLinq https://www.nuget.org/packages/morelinq/.
.Net 4.7.1 does not have .ToHashSet() methods. We used .ToHashSet() from MoreLinq library. And in the same class in the same cs-file we have both using System.Linq; and using MoreLinq;.
I retargeted a project to .Net 4.7.2 and the compiler showed The call is ambiguous error as described above. The reason was that .Net 4.7.2 added new extension methods with the same name .ToHashSet().
I cannot reimplement huge code base. I cannot replace MoreLinq with another library. This is what I did. I created a new class in a new file where I have using System.Linq; but not using MoreLinq;. This is the file (ToHashsetHelpers.cs):
using System.Collections.Generic;
using System.Linq;
namespace Common.Helpers
{
/// <summary>
/// This class with only one method helps to resolve
/// name conflict between .Net 4.7.2 and MoreLinq libraries.
///
/// .Net 4.7.2 introduced a new extension method named '.ToHashSet()'.
/// But MoreLinq already has the same method.
///
/// After migrating our solution from .Net 4.7.1 to 4.7.2
/// C# compiler shows "The call is ambiguous" error.
///
/// We cannot have both "using System.Linq;" and "using MoreLinq;" in the same C# file that
/// uses '.ToHashSet()'.
///
/// The solution is to have method with different name in a file like this.
/// </summary>
public static class ToHashsetHelpers
{
/// <summary>
/// The name of this method is ToHashset (not ToHashSet)
/// </summary>
public static HashSet<TSource> ToHashset<TSource>(this IEnumerable<TSource> source)
{
// Calling System.Linq.Enumerable.ToHashSet()
return source.ToHashSet();
}
}
}
And I renamed all .ToHashSet() to .ToHashset() in entire solution.

I was wondering about the same question and I did a quick test inside an asp.net core 6 project.
If you try this, it does not compile. Pretty much similar as other ambiguous calls or statements not involving extension methods.
using TestExtNs;
using TestExtNs2;
namespace YourBlazorProject.Server
{
public class TestMe
{
public void Test() { }
}
}
namespace TestNs
{
public static class Tester
{
public static void RunTest() // Exec this
{
var x = new YourBlazorProject.Server.TestMe();
x.Test();
x.TestExt(); // does not compile !!! error CS0121
TestExtNs.TesterExt.TestExt(x); //explicit call as working alternative
}
}
}
namespace TestExtNs
{
public static class TesterExt
{
public static void TestExt(this YourBlazorProject.Server.TestMe y)
{
Console.WriteLine("ExtNs");
System.Diagnostics.Debug.WriteLine("#> DIAG: ExtNs");
}
}
}
namespace TestExtNs2
{
public static class TesterExt
{
public static void TestExt(this YourBlazorProject.Server.TestMe y)
{
Console.WriteLine("ExtNs2");
System.Diagnostics.Debug.WriteLine("#> DIAG: ExtNs2");
}
}
}
Alternative: If there is an extension method in the same namespace, this 'closer one' is used; otherwise it won't compile.
// SomeTest.cs (example for 'closer namespace')
using TestExtNs; // This is hard REQUIREMENT for bringing the extension method from TestExtNs into scope !!!
namespace YourBlazorProject.Server
{
public class TestMe
{
public void Test() { }
}
}
namespace TestNs
{
public static class Tester
{
public static void RunTest() // Exec this
{
var x = new YourBlazorProject.Server.TestMe();
x.Test();
x.TestExt(); //Ns
TestExt(x); //Ns
TestExtNs.TesterExt.TestExt(x); //ExtNs
}
public static void TestExt(this YourBlazorProject.Server.TestMe y)
{
Console.WriteLine("Ns"); //writes to the Console Window of the *.Server.exe if its out-of-process hosted. if hosted on IISExp then its visbible in if IISExp is launched from console according to stackoverflow.
System.Diagnostics.Debug.WriteLine("#> DIAG: Ns"); //writes to the VS output console
}
}
}
namespace TestExtNs
{
public static class TesterExt
{
public static void TestExt(this YourBlazorProject.Server.TestMe y)
{
Console.WriteLine("ExtNs");
System.Diagnostics.Debug.WriteLine("#> DIAG: ExtNs");
}
}
}
Output:
Ns
Ns
ExtNs

Related

c# harmony example not print injection logs as expected

the C# harmony documentation: https://github.com/pardeike/Harmony/wiki/Prioritiy-annotations
my question is that not able to run the C# harmony example successfully
the postfix annotation didn't get injection log printed as expected after Class and method get patched that i didn't see "injection logs" get printed.
c# code example below. Can someone help me find the issue
you may paste into https://dotnetfiddle.net/ to debug it.
using System;
using System.Collections.Generic;
using System.Reflection;
using Harmony;
public class Program
{
public static void Main()
{
var harmony = HarmonyInstance.Create("net.example.plugin");
harmony.PatchAll(Assembly.GetExecutingAssembly());
Program p = new Program();
p.Bar();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Program), "Bar")]
public static void Postfix_Bar(){
Console.WriteLine("postfix Bar log"); // this never gets printed as expected.
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Program), "Foo")]
public static void Postfix_Foo(ref string res){ //however, this gets error res could not be found. https://github.com/pardeike/Harmony/wiki/Prioritiy-annotations
Console.WriteLine("postfix Foo log");
res = "new value";
}
public void Bar() {
Console.WriteLine("Hello World !!! ");
}
static string Foo()
{
return "secret";
}
}
The main problem is that PatchAll() looks for classes that have at least on [HarmonyPatch] annotation. Your patches are in the class Program which does not have that annotations. This is the main problem in your example.
Solution: either annotate your Program class like this:
[HarmonyPatch]
public class Program
{
}
or create a new class that has that annotation.
The second problem I can see is that Postfix_Foo(ref string res) uses res which does not follow the documented standard for naming patch arguments. It can either be the name of an argument that the original method has (it has no arguments) or refer to the result, which requires it to be named __result.
The comment about priority annotations is misplaced too because they only apply to multiple patches to the same original method.
Finally, you call Bar() after patching which means that Foo is never called - not sure if that’s intended.

Create and Using DLL in same Project in c#

I am having a DLL file. With the use of DLL, I have to call the methods and add some more methods in my project. Now, I need to migrate the older DLL to Make that project as a new DLL. I done this But the problem is The C# code is converted to net module it shows two errors. I am not clear about that. kindly help me over it.
DLL Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace mcMath
{
public class mcMathComp
{
private bool bTest = false;
public mcMathComp()
{
// TODO: Add constructor logic here
}
/// <summary>
/// //This is a test method
/// </summary>
public void mcTestMethod()
{ }
public long Add(long val1, long val2)
{
return val1 - val2;
}
/// <summary>
/// //This is a test property
/// </summary>
public bool Extra
{
get
{
return bTest;
}
set
{
bTest = Extra;
}
}
}
}
CS Project:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using mcMath;
namespace mcClient
{
class Program
{
static void Main(string[] args)
{
mcMathComp cls = new mcMathComp();
long lRes = cls.Add(23, 40);
cls.Extra = false;
Console.WriteLine(lRes.ToString());
Console.ReadKey();
}
}
}
Errors:
Program.cs(5,7): error CS0246: The type or namespace name 'mcMath' could >not be found (are you missing a using directive or an assembly reference?)
Tried Methods:
I will add the reference via Project-> Add Reference.
The using Reference also used.
Put the DLL into the current project debug/release folder
I'm guessing you used to have the code side by side, i.e.
public int Add(int a, int b)
{
return a + b;
}
public void SomeMethod()
{
var result = Add(2,3);
}
This works because the scope (this.) is applied implicitly, and takes you to the Add method on the current instance. However, if you move the method out, the scope is no longer implicit.
You will need one of:
the type name if it is a static method
or a static using if using C# 6
a reference to the instance if it is an instance method
Then you would use one of (respectively):
var result = YourType.Add(2,3); (plus using YourNamespace; at the top)
using static YourNamespace.YourType; at the top
var result = someObj.Add(2,3);
Checking the compiler message, it sounds like you've done something like (line 7):
using YourNamespace.YourType.Add;
which is simply wrong; you don't use using to bring methods into scope - only namespaces and (in C# 6) types.
Likewise, I suspect you have (line 22):
var result = YourNamespace.YourType.Add(x,y);
which is not valid as this is not a static method.
Create and Using DLL in same Project in c#
DLL or Class Library is a separate project that can be part of same solution.
As you already know, adding a reference to that dll/project will make it available in your app project.
However if function Add in dll is in different namespace (which would be normal) u would need to add using clause at the beginning of your class

Namespace issue with period

I have a class:
namespace FooIOS
{
public class Foo
{
public static void doThis() {...}
}
}
And this works:
using FooIOS;
namespace Sample.iOS
{
public void method () {
Foo.doThis();
}
}
However, this does not work the same way when I change the namespace to insert a period:
namespace Foo.iOS
{
public class Foo
{
public static void doThis() {...}
}
}
using Foo.iOS;
namespace Sample.iOS
{
public void method () {
// Compilation error
Foo.doThis();
// Compilation error
Foo.iOS.doThis()
// This works but I can't have it that long and complicated (I'm writing an API call)
Foo.iOS.Foo.doThis();
}
}
I'm pretty inexperienced with C# and I'm wondering if there's any way to use the period in the namespace and not deal with the complicated call.
namespace Foo.iOS
{
public class Foo
{
public static void doThis() {...}
}
}
Your namespace name is Foo.iOS, class name is Foo, static method name is doThis(). The fully qualified path to access that method is NAMESPACE.CLASS.METHOD_NAME, so it becomes:
Foo.iOS.Foo.doThis();
Here is nothing wrong with C#, but with the naming you use.
From this a couple of suggestions:
try to no use . inside names of the namespace, as this introduces confusion
try to not name namespace as the class inside it, as this introduces confusion.
I'm pretty inexperienced with C# and I'm wondering if there's any way
to use the period in the namespace and not deal with the complicated
call.
Short answer is: name your namespaces, classes and member functions in a way, that it does not look complicated to you and to others.
EDIT
Consider that you can use also Namespace Alias.
For example:
using IOS = Foo.iOS;
...
IOS.Foo.doThis();
But as I said before, it's better to avoid . in namespace name at first place.
Bring the using Foo.iOS; statement inside the namespace Sample.iOS namespace block, like shown below, then you will be able to call doThis() like in your 1st attempt Foo.doThis(); that was previously giving you a compile error.
namespace Sample.iOS
{
using Foo.iOS;
public void method () {
// this works
Foo.doThis();
}
}
Related reading: Inside or Outside? by Eric Lippert on MSDN.
Fully working Code sample:
Create a new Console App in Visual Studio, and then in the Program.cs class, delete all lines, paste the following, do a compile and then run.
using System;
namespace Foo.iOS
{
public class Foo
{
public static void doThis() { Console.Write("Inside doThis");}
}
}
namespace Sample.iOS
{
using Foo.iOS;
class Program
{
static void Main(string[] args)
{
method();
Console.ReadKey();
}
public static void method ()
{
// works fine
Foo.doThis();
}
}
}

How to call an extension method without using

using System;
class Runner
{
static void Main()
{
A a = new A();
// how to say a.PrintStuff() without a 'using'
Console.Read();
}
}
class A { }
namespace ExtensionMethod
{
static class AExtensions
{
public static void PrintStuff(this A a)
{
Console.WriteLine("text");
}
}
}
How would I call the extension method without a 'using'? And not ExtensionMethod.AExtensions.PrintStuff(a), since that doesn't make use of extension method.
It is possible to directly call your extension like so since it is simply a static method, passing the instance it will act on as the first this parameter:
A a = new A();
ExtensionMethod.AExtensions.PrintStuff(a);
This might be confusing to other developers who happen across this code if you followed this pattern for more commonly used extension methods. It would also make chaining extension calls such as LINQ appear more like a functional language because you would be nesting each call instead of chaining them.
that is possible if Extension Method and class A in same namespace,
If you have to use different namespaces then you have to use using, i don't think there is a way to do this without using. But you may reduce the number of using by putting all the extensions in one namespace like for Linq (System.Linq.Extensions)
Note : You can remove the namespace for Extension methods, then it will make them globally available
It needs the using to know where the function lives.
One example of this in Linq. Without the System.Linq using - you won't have linq enabled for any of your IEnumerable<T>'s
However, you can define the extension method in the same namespace as the caller to avoid putting in a using. This approach will however not work if it's needed in many namespaces
This makes me feel dirty, but you can put your extension methods in the System namespace.
This namespace is included by default in your question
using System;
class Runner
{
static void Main()
{
A a = new A();
// how to say a.PrintStuff() without a 'using'
Console.Read();
}
}
class A { }
namespace System
{
static class AExtensions
{
public static void PrintStuff(this A a)
{
Console.WriteLine("text");
}
}
}
Ruminations on the creation of extension methods for a type ExtendableType:
Name the class ExtendableTypeExtensions
Declare the extension class partial so that clients can add extension methods following the same pattern; and
Put the extension methods in the same namespace as the base type
unless you have a very good reason to follow a model like that of LINQ:
A substantial family of extension methods,
That all apply to multiple base classes.
As of C# v6.0 (circa 2015) you can use using static to access a specific class's static members without including it's whole namespace.
An example, using your code, would be:
using System;
using static ExtensionMethod.AExtensions;
class Runner
{
static void Main()
{
A a = new A();
a.PrintStuff();
Console.Read();
}
}
class A { }
namespace ExtensionMethod
{
static class AExtensions
{
public static void PrintStuff(this A a)
{
Console.WriteLine("text");
}
}
}
You can add extensions method without namespace.
This will affect the whole systems which is not recommended.
public static class StringExtensions
{
public static void HelloWorld(this String s)
{
Console.Write("Hello World");
}
}
string str = "s";
str.HelloWorld();
In our projects extensions are placed in the same namespace as class extension for. Your example:
A.cs:
using System;
namespace ANamespace
{
class A { }
}
AExtensions.cs:
namespace ANamespace
{
static class AExtensions
{
public static void PrintStuff(this A a)
{
Console.WriteLine("text");
}
}
}
Now when you add using for ANamespace for using the A class, all extensions for A class will be included too.

Is it possible to write a extension method for an abstract class

Why I'm unable to extend an abstract class. Is there any work around to achieve this?
In silverlight, Enum.GetNames is missing. So, I would like to extend it and have it in my utility assembly. By then, got into this.
The problem here is not that you can't add an extension method to an abstract class (you can - you can add an extension method to any type) - it's that you can't add a static method to a type with extension methods.
Extension methods are static methods that present themselves in C# as instance methods. But they're still static. Adding a static method to a type requires the ability to redefine the type, which you can only do if you have the source code :)
Best bet, if you want this method, is to write your own static and see if you can perhaps rip the code out of reflector.
However, it's entirely possible that it's not there because it's physically not supported in Silverlight (I don't know - I haven't investigate)
EDIT
Following on from your comment - and I hope that I've understood you here - I think what you want to be able to do is something like this (targetting object to prove the point):
public static class ExtraObjectStatics
{
public static void NewStaticMethod()
{
}
}
public class Test
{
public void foo()
{
//You can't do this - the static method doesn't reside in the type 'object'
object.NewStaticMethod();
//You can, of course, do this
ExtraObjectStatics.NewStaticMethod();
}
}
If you think about it - of course you can't inject new static methods into an existing type because, like I said in paragraph two, you have to be able to recompile the underlying type; and there simply is no way around that.
What you can do is (and I don't actually recommend this - but it's an option) create yourself a new type called Enum and place it inside a new namespace:
namespace MySystem
{
public class Enum
{
public static string[] GetNames()
{
//don't actually know how you're going to implement it :)
}
}
}
And now - when you want to use it, what you can't do is this:
using System;
using MySystem;
namespace MyCode
{
public class TestClass
{
public static void Test()
{
Enum.GetNames(); //error: ambiguous between System and MySystem
}
}
}
Because the using in the outermost scope to both 'System' and 'MySystem' will cause the compiler not to be able to resolve the correct Enum type.
What you can do, however, is this:
using System;
namespace MyCode
{
using MySystem; //move using to inside the namespace
public class TestClass
{
public static void Test()
{
//will now work, and will target the 'MySystem.Enum.GetNames()'
//method.
Enum.GetNames();
}
}
}
Now, code within that namespace (within that file only) will always resolve Enum to the one in your namespace because that's the nearest using directive in terms of scope.
So, you can think of this as overriding the whole Enum type for the benefit of a given namespace that includes a using MySystem; in it.
But, it does exactly that - it replaces the existing System.Enum with MySystem.Enum - meaning that you lose all the members of the System.Enum type.
You could get around this by writing wrapper methods in your Enum type around the System.Enum versions - making sure that you fully-qualify the type as System.Enum.
Having looked at the implementation of the GetNames method in Reflector - it relies on internal data that I don't think you're going to be able to build... but I would be very interested to hear if you are actually able to reproduce the method in Silverlight.
public abstract class Foo
{
public abstract void Bar();
}
public static class FooExtensions
{
// most useless extension method evar
public static void CallBar(this Foo me)
{
me.Bar();
}
}
Sure, no problem.

Categories