Extension methods in a class library project - c#

I've implemented some extension methods and put those in separate Class Library project.
Imagine I have a simple extension method like this in class library called MD.Utility:
namespace MD.Utility
{
public static class ExtenMethods
{
public static bool IsValidEmailAddress(this string s)
{
Regex regex = new Regex(#"^[\w-\.]+#([\w-]+\.)+[\w-]{2,4}$");
return regex.IsMatch(s);
}
}
}
But nowhere in the web app like the App_code folder or the WebFroms code-behind page can I use this extension method. If I do something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using MD.Utility;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string email = "Someone#Somewhere.com";
if (email.IsValidEmailAddress())
{
//To do
}
}
}
The compiler doesn't recognize IsValidEmailAddress() and there's even no IntelliSense support.
While if I put my extension method in the App_Code folder, it's usable in another .cs files in the App_code folder or the WebForms code-behind pages.

Did you remember to add a reference to your class library in the web project ?
You will need that. Other than that, your code looks fine, and should work.

If changes are not getting recompiled when you do a solution rebuild, then it could be the type of reference you are using. If the MD.Utility project is in your web project solution, you should make the reference a "Project Reference." That will cause the build to consider that code as a dependency and therefore rebuild it when you change something. If you just include it as a DLL, then the DLL is considered external and the build will not consider it, even if it is in the same solution.

I was able to resolve it by making the extension module public.
This post may be helpful:
Extension methods in referenced assemblies?

In addition to adding the assembly to the references, what fixed it for me was to explicitly adding it to the file "using MD.Utility".

I've found that this can occur if the Assembly Name and Namespace of the consuming project are the same and the Common library has the same Namespace.
Seems that the compiler gets confused. Try changing them.
As noted elsewhere, you need to add the Common library to each consuming project. And the Module containing the Extension(s) in the Common library must be marked Public. Unlike Classes, Public isn't the default scope for Modules. No idea why.

Related

System.Linq: The call is ambiguous between the following methods or properties

There is a old Asp.Net WebSite Project, opened in VS 2015 which targeting a 4.0 FrameWork Version, when I am trying to build it it gives me below error:
The call is ambiguous between the following methods or properties:
System.Linq.Enumerable.Contains<TSource>(System.Collections.Generic.IEnumerable<TSource>, TSource) and System.Linq.Enumerable.Contains<TSource>(System.Collections.Generic.IEnumerable<TSource>, TSource)
which both method signature looks exactly identical.
Here it code from the class:
using System;
using System.Collections.Generic; // Gray out
using System.Linq;
using System.Web; // Gray out
using System.Web.Routing;
using System.Web.UI; // Gray out
public class UrlRoute
{
public static string RegisterRoutes(string routes)
{
string MainUrl = routes;
string result = "";
if (MainUrl.Contains('\\')==true)
{
result = "CMS"
}
return result;
}
}
Project Properties:
Framework Details:
I tried solution from SO but none of them worked [delete bin folder, check unresolved references], don't understand the reason behind the error!
EDIT:
Same is happening for Last() and all that extension method from System.Linq:
Error CS0121 The call is ambiguous between the following methods or properties: 'System.Linq.Enumerable.Last(System.Collections.Generic.IEnumerable)' and 'System.Linq.Enumerable.Last(System.Collections.Generic.IEnumerable)'
Will love to share any other configuration/code if required.
You are most likely referencing two versions of System.Linq.dll. Project should use version from GAC, not local copy from BIN.
Try to find and remove explicit reference to System.Linq.dll in your C# project.
P.S. And if you have multiple projects in the solution, make sure they all target same version of .NET Framework.

Use existing source code in another project/namespace

I have two library projects within a single solution (in addition to other projects) which necessarily need to share certain classes but must remain separate for automatic-update reasons.
For the classes that are shared, I would ideally like to use the same class.cs file in both libraries so that I don't have to consistently check that changes to the class are propagated through both libraries.
However the namespaces of the two libraries are different, and so the class-containing file in each library requires a different namespace classlib {} declaration.
I am using a git repo, if there is a technique to do this through branch/merge operations.
Presently using VS2013.
How can I achieve this?
Example:
library1.dll
namespace library1
{
public class SharedClass
{
/// code must match SharedClass in libary2
}
}
library2.dll
namespace libary2
{
public class SharedClass
{
/// code must match SharedClass in library1
}
}
Declare the SharedClass in a common namespace, instead of two different namespaces. You could link the file into the projects instead of including it physically.
From msdn:
You link to a file from your project in Visual Studio. In Solution Explorer, right-click your project, and then select Add Existing item Or, you can type Shift+Alt+A. In the Add Existing Item dialog box, select the file you want to add, and in the Add drop-down list, click Add As Link.
namespace Khargoosh.MathLib.Common { public class SharedClass { ... } }
namespace Khargoosh.MathLib.Library1 { ... }
namespace Khargoosh.MathLib.Library2 { ... }
or
namespace Khargoosh.MathLib { public class SharedClass { ... } }
namespace Khargoosh.MathLib.Library1 { ... }
namespace Khargoosh.MathLib.Library2 { ... }
A completely other way of handling that would be to use the T4 template with some logic to create the file dynamically. Content of the *.tt template files (not *.cs files!):
namespace library1
{
<## include file="MyCommonClass.cs"#>
}
And in the other library
namespace library2
{
<## include file="MyCommonClass.cs"#>
}
The class file itself would not declare a namespace.
Based on the info you've provided, if your shared classes are truly "common" you should create a 3rd library that both of your main libs can reference. for example:
MainLib1
(reference commonLib)
MainLib2
(reference commonLib)
commonLib
(includes class.cs and other common code)
I need to be able to update the library.dll files separately
Then you should use submodules for this task.
Submodule are different git repositories under the same root.
This way you can manage 2 different project at folder level inside the root repository

Why cant I access .TrimSafe?

Copied some code from one controller to another. Both files have the same using statements but it wont 'resolve' this issue for me.
On my first file address.Name.Value = source.Name.TrimSafe();
is fine however on my second file. .TrimSafe flags up as does not exist
From the telescense i can choose trim, trimEnd or trimStart where has trimSafe gone to and why cant I use it?
TrimSafe() is not a standard .NET method. This would suggest that TrimSafe() exists as a method in your first file, but never got copied over to the second, and it's a either a private function or non-static function.
I would clean & rebuild your project as well.
It sounds like a namespace issue to me.
Consider this:
// In some file somewhere
namespace firstNamespace
{
Class MyString : String
{
public static TrimSafe() {}
}
}
// The first file you copied from
namespace firstNamespace
{
public void foo() { TrimSafe(); } // Works!
}
namespace secondNamespace
{
public void fee() { TrimSafe(); } // Nope :(
}
To fix the last one, you need to add using firstNamespace; at the top with the other using statements. The reason would be that the first file you're copying from is in the same namespace as where TrimSafe is defined.
In C++ you typically #include all of the referenced .h files for each class that you use.
In C#, you don't add using statements for classes, but instead for namespaces. You only need to be using the namespace, and everything inside of that namespace comes along with it. Anything defined in namespace xyz sees everything else defined in namespace xyz without having to have a using for each class.
Your second file is in a different namespace, and so it has no idea what is in the first namespace, and so it doesn't see TrimSafe.
That's my guess anyways.
Looks familiar, I guess you're doing the Orchard Webshop tutorials as well :)
You need to add a folder in your project called Helpers, and it should have this class in it:
public static class StringExtensions {
public static string TrimSafe(this string s) {
return s == null ? string.Empty : s.Trim();
}
}
Just include the namespace where your method is needed.

C#.NET Namespace name does not exist in namespace error - only when using is outside local namespace directive - why?

Using .NET 2.0, C#, Windows Forms development, Enterprise Library 3.1.
We have a project namespace (call it Project). We also have several sub-namespaces inside of that project, for example Project.Namespace1, Project.Namespace2, etc.
In one class, we define enums and such to be used with the Enterprise Library Logging block, like this:
namespace Project.Logging
{
public static class Logging
{
public enum LogPriority
{
// enum values here
}
}
}
In another class, I use the enum values so I need to declare a using statement. Same project, so there is no assembly to reference, right?
If I declare the using inside of the local namespace, like this, it works fine:
namespace Project.SomeName
{
using Project.Logging;
// code referencing the Logging enum
}
However, if I put the using statement outside of the local namespace declaration, I get the "type or namespace name 'LogPriority' does not exist in the namespace 'Project.Logging'... Like this:
using Project.Logging;
namespace Project.SomeName
{
// code referencing the Logging.LogPriority.whatever
}
Why is this? Has anyone run across this before?
I have run into similar (though not exactly the same) problems before when using a class that has the same name as its namespace.
Oddly enough it seemed to compile ok on some developers pc's but not on others. In the end we made sure that no namespace contained a class of the same name.
namespace Project.Logging
{
public static class Logging // this is what caused the probems for me
{
}
}
I also had a wired error. I cannot find any namespace which is coming from different assemblies, but begins with executing assembly name.
Finally, I found out that I have set the target framework to .NET framework client profile.
Yes, most likely you have an unusual value set for the "Default Namespace" in your project properties. I would validate the project configuration.
We ran into this issue before and it all went down to ambiguous naming of the namespace and the class name.
When we tried to have our namespace as Services.Web.xxx and also add in a service reference as Services.Web.xxxx and ALSO add a references to an assembly that was named Services.Web.xxx you can only imagine the problems we ran into.
In the end to fix it we simply did a rename to make sure that there was only one instance of the Services prefix
Also you could do the following and create an alias to LogPriority to LogEnum:
using LogEnum= Project.Logging.Logging.LogPriority;
namespace Project.SomeName
{
internal class MyClass
{
public MyClass()
{
LogEnum enum1 = LogEnum.None;
}
}
}
namespace Project.Logging
{
public static class Logging
{
public enum LogPriority
{
None,
Default
}
}
}
It definitely can make a difference if you have usings inside or outside the namespace. There is a good discussion here, and it is likely to be related to your default namespace settings.

warning MSB3391: <DLL> does not contain any types that can be unregistered for COM Interop

I've made a simple C# DLL (that's part of a much larger project) using VS2005. I need to use the DLL in Excel via VBA code so I am using COM Interop on the assembly. I am trying to make the build process automatically generate the necessary TLB file so that I don't need to go to the command line and use regasm after every build.
My problem is that although the DLL compiles and builds fine, it does not generate a TLB file. Instead, the error in the title prints out in the output box.
I've gotten other DLLs to build TLB files by going to the project's properties in VS2005 -> Build -> Output -> Check "Register for COM interop". Also I have [assembly: ComVisible(true)] in the AssemblyInfo.cs.
Here's the summary of the source for the problem DLL and the DLL that it references for a return type:
using System;
using System.IO;
using System.Runtime.InteropServices;
using SymbolTable;
namespace ProblemLibrary
{
public class Foo
{
public Foo(string filename)
{
...
}
// method to read a text file into a SymbolTable
public SymbolTable BuildDataSet(string[] selected)
{
...
}
}
}
Here is a summary of SymbolTable.dll. It holds a return type that ProblemLibrary uses.
using System;
using System.Collections.Generic;
namespace SymbolTable
{
public class SymbolTable
{
readonly Dictionary<SymbolInfoStub, string> _symbols = new Dictionary<SymbolInfoStub, string>();
/*methods that interact with Dictionary snipped*/
}
}
You need to have ctor without any params.
You should have GuidAttribute and ProgIdAttribute around the classes.
Its better to mark the assembly as ComVisible(false) and mark explicitly the classes that need export.
Use interfaces for your classes.
Make sure the you have GuidAttribute in the assembly level.
[Guid("<PUT-GUID-HERE-1>")]
[ComVisible(true)]
interface IFoo
{
void DoFoo();
}
[Guid("<PUT-GUID-HERE-2>")]
[ComVisible(true)]
[ProgId("ProgId.Foo")]
class Foo : IFoo
{
public void DoFoo()
{
}
}
In the AssemblyInfo.cs file, make sure you have the following:
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(true)]
UPDATE:
Read: How can I make use of .NET objects from within Excel VBA?
Which links to:
http://richnewman.wordpress.com/2007/04/15/a-beginner%E2%80%99s-guide-to-calling-a-net-library-from-excel/
I saw a similar problem. I got an error like:
warning MSB3391: does not contain any
types that can be unregistered for COM
Interop.
I followed all the rules (ComVisible, etc.) but nothing worked.
Solution: I had to put something in the default constructor so that it would not be optimized away. The moment I had something there, the registration finished with no message and the component was visible in the registry.
Interesting note: a friend of mine managed to register the original DLL with the empty default constructor on his machine (64-bit Windows-7, VS2008-Professional, like mine). However, his REGASM.EXE was:
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\regasm.exe
while mine was:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe
So it could be some difference between versions of the .NET framework - maybe the later version is optimizing too much and the REGASM does not account for that.

Categories

Resources