Confused about C#'s extension method overload resolution - c#

Consider the following code:
using System;
using System.Linq;
using System.Collections.Generic;
public static class Ex
{
public static IEnumerable<T> Take<T>(this IEnumerable<T> source, long cnt)
{
return source;
}
}
public class C
{
public static void Main()
{
foreach(var e in Enumerable.Range(0, 10).Take(5).ToArray())
Console.Write(e + " ");
}
}
I have an extension on IEnumerable<T> for Take(long), which isn't provided by the framework. The framework only provides Take(int). And since I'm calling it with an int parameter (Take(5)), I would have expected it to use the framework version, but it's calling my extension.
Am I missing something? The closest match would obviously be the one that takes int as a parameter, and System.Linq is included so it should be in the pool of valid overloads. In fact if I delete my extension, the correct framework function is called.
For reference
Edit: Moving them to different namespaces shows the same problem:
using System;
using System.Linq;
using System.Collections.Generic;
namespace N1
{
public static class Ex
{
public static IEnumerable<T> Take<T>(this IEnumerable<T> source, long cnt)
{
return source;
}
}
}
namespace N2
{
using N1;
public class C
{
public static void Main()
{
foreach(var e in Enumerable.Range(0, 10).Take(5).ToArray())
Console.Write(e + " ");
}
}
}
For reference

Because as Eric Lippert puts it:
the fundamental rule by which one potential overload is judged to be
better than another for a given call site: closer is always better
than farther away.
Closer is better

Try System.Linq.Enumerable.Take(source, 5) instead of just Take(source, 5) to force using the original "Take" function or rename your own "Take" into somthing else "Takef" for example to avoid this kind of problems.

Related

Create Unit Tests is supported only within a public class or a public method VS 2015

I'm getting a Create Unit Tests is supported only within a public class or a public method when I try to create unit tests for my app. I was trying to test a public method in a very simple app in Visual Studio 2015 Enterprise. Here's a screenshot.
Here's the Program.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Scratch
{
public class Program //Originally this was just class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello world!");
}
public static string TruncateOld(string value, int length)
{
string result = value;
if (value != null) // Skip empty string check for elucidation
{
result = value.Substring(0, Math.Min(value.Length, length));
}
return result;
}
public static string Truncate(string value, int length)
{
return value?.Substring(0, Math.Min(value.Length, length));
}
}
}
I've found this msdn article, but it doesn't really offer any suggestions on how to solve the problem. Also, I've never installed 'ALM Rangers Generate Unit Test.'
I got rid of everything from my Program.cs except for the Main and added a new Public Class1 with the following code (I still get the error and the menu goes away):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Scratch
{
public class Class1
{
public Class1()
{
}
public string TruncateOld(string value, int length)
{
string result = value;
if (value != null) // Skip empty string check for elucidation
{
result = value.Substring(0, Math.Min(value.Length, length));
}
return result;
}
public string Truncate(string value, int length)
{
return value?.Substring(0, Math.Min(value.Length, length));
}
}
}
To anyone that is new to C# having this issue, you need to add the public keyword to your class.
For example,
class myProgram
{
static void Main(string[] args)
{
Console.WriteLine("Hello World");
}
}
You'd need to change the first line to public class myProgram
Probably coming to the party too late, but since I had the same problem and was able to solve it, you never know who is going to need it. So... as soon as I removed the reference to the Microsoft.VisualStudio.QualityTools.UnitTestFramework
the "Create Unit Tests" option reappeared in the context menu and I was able to create the tests I needed.
So I know this is late, and not really an answer to the above question due to your class definition, but I don't see enough forums on this error, so I decided to add my findings here.
I found that if you have a class with only properties and no true methods, 'Create Unit Tests' will not work. Even if your properties are public and have complex getters or setters. Here was the state of my code when running into this problem, as I just made the class:
namespace some.Namespace
{
using some.Namespace.Interfaces;
using System;
using System.Collections.Generic;
public class SomeData : ISomeData
{
public bool SomeFlag => throw new NotImplementedException();
public Dictionary<string, string> SomeFields => throw new NotImplementedException();
public Dictionary<string, string> SomeOtherFields => throw new NotImplementedException();
}
}
However, you can work around this by either defining at least constructor or by temporarily making some random method. However, note that tests will only be made for true methods in your class so you will still have to manually write the tests for your properties' getters/setters.
Hope someone finds this answer helpful.
Apparently, this is still a rabbit hole to fall into, as I stepped into it today. In my case, running on VS 2019 Enterprise. My error was having NuGet packages installed on the test project which isn't needed. I had added NuGet packages MSTest.TestAdapter, and Microsoft.TestPlatform. Removing both, closing and reopening the IDE restored the wizard for creating a Test Method. For an initial or new test project, the only NuGet package needed for getting started is Microsoft.VisualStudio.TestPlatform.
If you mean the built in Visual Studio 2015 test cases, you need to take out the static from the public members. Like this:
[TestClass]
public class UnitTests
{
[TestMethod]
public void Testing_01()
{
Assert.IsTrue( [some bool condition] );
}
}

Why I have to write the namespace to access to this extension method?

I have a project that has class to implement extension methods for some type. For example I have this class for ObservableCollection:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
namespace MyProject.Collections.Utils
{
public static class ObservableCollection
{
public static void RemoveAll<T>(this ObservableCollection<T> collection, Func<T, bool> condition)
{
for (int i = collection.Count - 1; i >= 0; i--)
{
if (condition(collection[i]))
{
collection.RemoveAt(i);
}
}
}//RemoveAll
}
}
With this class, in my main project I can use this library with the using:
using MyProject.Collections.Utils
And when I want to use the extension methods I can do:
ObservableCollection<MyType> myOC = new ObservableCollection<MyType>();
myOC.RemoveAll(x=>x.MyProperty == "123");
So I have access to my extension method.
However, I have another class for Decimal, is this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyProject.Decimal.Utils
{
public static class Decimal
{
public static decimal? Parse(this string paramString)
{
try
{
myCode
}
catch
{
throw;
}
}//Parse
}
}
But in this case, although in my main prject I import the class:
using MyProject.Decimal.Utils;
If I do this:
decimal? myDecimalParsed= Decimal.Utils.Decimal.Parse("123");
Why in this case I can't do this?:
decimal? myDecimalParsed= decimal.Parse("123");
thank so much.
Two problems:
You can't use extension methods as if they were static methods of the extended type
System.Decimal already has a Parse method, and the compiler always looks for "real" methods before extension methods.
In fact, you can write
decimal? miTiempoEstimadoParseado = decimal.Parse("123");
... but that will just call the normal method and then convert the decimal to decimal? implicitly in the normal way.
Note that you're not really using your method as an extension method at the moment anyway - to do so you'd write something like:
decimal? miTiempoEstimadoParseado = "123".Parse();
... but personally I'd view that as pretty ugly, partly as the method name doesn't indicate the target type at all, and partly because by convention Parse methods throw an exception instead of returning a null value on failure. You probably want to come up with a different name.

C# Beginner problems

I have a "Debug" class, which simply prints information to the console etc. From the rest of the code I want to be able to call the methods within it, but so far it's only partly working.
Calling dc.Print() works fine, but as soon as I call dc.Print(dc.GetEventsLogged()) I get a red line with the message
"The best overloaded method match has some invalid arguments" as well as Argument 1: cannot convert from 'int' to 'string'.
Basically: Why are my arguments to dc.Print wrong? Also, what can I do about "cannot convert from int to string? I tried .ToString but that didn't work either.
This is my "Debug.cs" class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Test
{
public class Debug
{
private int events_logged;
public Debug()
{
events_logged = 0;
}
public void Print(string Message)
{
Console.WriteLine("[" + DateTime.UtcNow + "] " + Message);
events_logged++;
}
public int GetEventsLogged()
{
return events_logged;
}
}
}
And in my "Program.cs" class I have:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Test
{
class Program
{
static void Main(string[] args)
{
Debug dc = new Debug();
dc.Print("Test");
}
}
}
The reason you are seeing the error is because GetEventsLogged() returns an int whereas Print() expects you to pass in a string. Therefore you need to the return from int to string and you were on the right track with ToString(). This will do what you want to achieve:
dc.Print(dc.GetEventsLogged().ToString());
dc.Print() wants a string argument and dc.GetEventsLogged() returns an int. You need to ToString() the int so that the types match.
int numberOfEventsLogged = dc.GetEventsLogged();
string numberOfEventsLoggedAsString = numberOfEventsLogged.ToString();
dc.Print(numberOfEventsLoggedAsString)
try dc.Print(dc.GetEventsLogged().toString()) because GetEventsLogged() is of int type and Print(string Message) looking for string input.
Your method Print expects an argument of type String. When you call dc.Print(dc.GetEventsLogged()), your actually give an int because your method GetEventsLogged() returns an int.
public string GetEventsLogged()
{
return events_logged.ToString();
}

C# caching with delegates

I'm working on a simple cache class for my application.
using System;
namespace Program {
public class Cache {
public delegate int CacheMethodInt();
public static int Get(CacheMethodInt method) {
//todo: generate cachekey here
return method.Invoke();
}
}
public class Calculator {
public int Add(int x, int y) {
return x + y;
}
}
class Program {
static void Main(string[] args) {
Calculator c = new Calculator();
Console.WriteLine(Cache.Get(() => c.Add(1, 2)));
}
}
}
In Cache:Get I need to check whether the return value is already cached and if so return it without invoking the method. The problem is that I can't figure out how to generate a good cachekey. In this case I would like something like this:
Calculator:Add:1(int):2(int)
Is it possible to get this info in Cache:Get? I'm using .NET 2.0.
It's possible using reflection.
As alternative, on a project I used Postsharp for the same purposes. As benefit more generic and common approach
And do not forget about cache invalidation or expiration.
Related question shows how to get MethodInfo and method name:
Using MethodInfo.GetCurrentMethod() in anonymous methods
When you have MethodInfo than you can get all you need

C# and Reflection

I'm a brand-newbie to C#, albeit not programming, so please forgive me if I mix things up a bit -- it's entirely unintentional. I've written a fairly simple class called "API" that has several public properties (accessors/mutators). I've also written a testing console application that uses reflection to get an alphabetically list of names & types of each property in the class:
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using MyNamespace; // Contains the API class
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hi");
API api = new API(1234567890, "ABCDEFGHI");
Type type = api.GetType();
PropertyInfo[] props = type.GetProperties(BindingFlags.Public);
// Sort properties alphabetically by name.
Array.Sort(props, delegate(PropertyInfo p1, PropertyInfo p2) {
return p1.Name.CompareTo(p2.Name);
});
// Display a list of property names and types.
foreach (PropertyInfo propertyInfo in type.GetProperties())
{
Console.WriteLine("{0} [type = {1}]", propertyInfo.Name, propertyInfo.PropertyType);
}
}
}
}
Now what I need is a method that loops through the properties and concats all the values together into a querystring. The problem is that I'd like to make this a function of the API class itself (if possible). I'm wondering if static constructors have something to do with solving this problem, but I've only been working with C# for a few days, and haven't been able to figure it out.
Any suggestions, ideas and/or code samples would be greatly appreciated!
This is unrelated to static constructors. You can do it with static methods:
class API {
public static void PrintAPI() {
Type type = typeof(API); // You don't need to create any instances.
// rest of the code goes here.
}
}
You can call it with:
API.PrintAPI();
You don't use any instances when you call static methods.
Update: To cache the result, you can either do it on first call or in an static initializer:
class API {
private static List<string> apiCache;
static API() {
// fill `apiCache` with reflection stuff.
}
public static void PrintAPI() {
// just print stuff from `apiCache`.
}
}

Categories

Resources