I built my solution properly in Visual Studio, but when I build with TFS, I have several errors such as:
path\file.cs (8, 47)
path\file.cs(8,47): Error CS1002: ; expected
path\file.cs (8, 85)
path\file.cs(8,85): Error CS1519: Invalid token '(' in class, struct, or interface member declaration
Screen:
namespace path
{
public class file : Ifile
{
public IContactService ContactService => Locator.GetService<IContactService>();
public IAddressService AddressService => Locator.GetService<IAddressService>();
}
}
Thank you for helping me!
public IContactService ContactService => Locator.GetService<IContactService>();
This is an expression-bodied property and is implemented only in CSC 6 and later. Your TFS is probably running CSC 5 or earlier. You have to change it to:
public IContactService ContactService
{
get { return Locator.GetService<IContactService>(); }
}
Related
RE: DotNet 6.0 and VS Community 2022 (64-bit) - CurrentVersion 17.1.1
This code results in a compiler error CS0246:
using GloboTicket.TicketManagement.Domain.Entities;
namespace GloboTicket.TicketManagement.Application.Contracts.Persistence
{
public interface IOrderRepository: IAsyncRepository<Order>
{
}
}
This following code does not (note the use of the prefix "Persistence." to refer to IAsyncRepository):
using GloboTicket.TicketManagement.Domain.Entities;
namespace GloboTicket.TicketManagement.Application.Contracts.Persistence
{
public interface IOrderRepository: Persistence.IAsyncRepository<Order>
{
}
}
Why is this needed? IAsyncRepository and IOrderRepository are siblings in the same folder - i.e., in the same namespace!
The reference can be used without the "Persistance." prefix if the "where T : class" is deleted in the base type "IAsyncRepository":
namespace GloboTicket.TicketManagement.Application.Contracts.Persistence
{
public interface IAsyncRepository<T> where T : class
{
/...
}
}
I am writing a source generator but am struggling to get the value of an argument passed to the constructor of my attribute.
I inject the following into the compilation:
namespace Richiban.Cmdr
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class CmdrMethod : System.Attribute
{
private readonly string _alias;
public CmdrMethod(string alias)
{
_alias = alias;
}
}
}
And then in my sample application I have the following:
public static class InnerContainerClass
{
[CmdrMethod("test")]
public static void AnotherMethod(Data data)
{
Console.WriteLine($"In {nameof(AnotherMethod)}, {new { data }}");
}
}
This compiles without errors or warnings and I am successfully able to find all methods that have been decorated with my CmdrMethod attribute, but I am unable to get the value passed to the attribute because, for some reason, the ConstructorArguments property of the attribute is empty:
private static ImmutableArray<string> GetAttributeArguments(
IMethodSymbol methodSymbol,
string attributeName)
{
var attr = methodSymbol
.GetAttributes()
.Single(a => a.AttributeClass?.Name == attributeName);
var arguments = attr.ConstructorArguments;
if (methodSymbol.Name == "AnotherMethod")
Debugger.Launch();
return arguments.Select(a => a.ToString()).ToImmutableArray();
}
Have I misunderstood this API? What am I doing wrong?
The Compilation is immutable. When you add the source code for your attribute, you still have a Compilation object that don't know anything about the attribute. This causes the AttributeClass to be an ErrorType as #jason-malinowski mentioned. This is very known for this kind of source generators, and the solution is just simple. Create a new Compilation with the symbol you injected, then get a SemanticModel from the new Compilation:
// You should already have something similar to the following two lines.
SourceText attributeSourceText = SourceText.From("CmdrMethod source code here", Encoding.UTF8);
context.AddSource("CmdrMethod.g.cs" /* or whatever name you chose*/, attributeSourceText);
// This is the fix.
ParseOptions options = ((CSharpCompilation)context.Compilation).SyntaxTrees[0].Options;
SyntaxTree attributeTree = CSharpSyntaxTree.ParseText(atttributeSourceText, (CSharpParseOptions)options);
Compilation newCompilation = context.Compilation.AddSyntaxTrees(attributeTree);
// Get the semantic model from 'newCompilation'. It should have the information you need.
UPDATE: The experience became better starting from Microsoft.CodeAnalysis 3.9 packages, you can now add the attribute in Initialize instead of Execute:
public void Initialize(GeneratorInitializationContext context)
{
// Register the attribute source
context.RegisterForPostInitialization((i) => i.AddSource("CmdrMethod.g.cs", attributeText));
// .....
}
Then, you can directly work with the compilation you get in Execute.
See AutoNotify sample.
The AttributeClass property is an ErrorType, which means that the compiler didn't actually know what that type was. We fill in a fake "error" type when we had a name for the type but otherwise didn't know what it was; this makes some downstream handling easier for certain features. In any case, figure out where that's coming from. You commented that "This compiles without errors or warnings" but whatever environment your Roslyn code is running in, you likely have a compilation that will give errors.
this question has been answered a few times but I still can not get my code to work. I have a very simple class looking like this:
namespace SportsStore.Controllers {
public class ProductController : Controller {
private IProductRepository repository;
public ProductController(IProductRepository repo) {
repository = repo;
}
public ViewResult List() => View(repository.Products);
}
}
With IproductRepository.cs
namespace SportsStore.Models
{
interface IProductRepository {
IQueryable<Product> Products { get; }
}
}
The error I get is of course is this one:
Severity Code Description Project File Line Suppression State
Error CS0051 Inconsistent accessibility: parameter type
'IProductRepository' is less accessible than method
'ProductController.ProductController(IProductRepository)' SportsStore
I can see that the problem is that I shouldn't set the IproductRepository variable to private and then have the ProductController public.
I read this answer:
Inconsistent Accessibility: Parameter type is less accessible than method
and it basically tells me that the class needs to be public (it already is) and the parameter needs to be 'as accessible as'. Meaning public, right?
But if I set the parameter to public aswell, like this:
public IProductRepository repository;
Then I still get this error:
Severity Code Description Project File Line Suppression State
Error CS0052 Inconsistent accessibility: field type 'IProductRepository'
is less accessible than field 'ProductController.repository' SportsStore
How do I fix this?
Note: This is an example from the book Asp Net Core by Adam Freeman and the github for the project is available at this link, in which the code is witten as I have above, so they have made no corrections to it. It seems like it should be working. Am running Visual Studio 2017 if that makes any difference.
https://github.com/Apress/pro-asp.net-core-mvc-2/blob/master/08%20-%20SportsStore/SportsStore/SportsStore/Controllers/ProductController.cs
Looks like the interface should be public
namespace SportsStore.Models
{
public interface IProductRepository
{
IQueryable<Product> Products { get; }
}
}
Same applies for classes that you pass to the constructor.
The Xamarin.Auth project broke up i.e. the source code was compiling OK and after another Xamarin.Android update it was suddenly broken.
It turned out that the problem arose after the Mono.Android.dll (Xamarin.Android) was extended by several namespace definitions.
I hunted the problem down to the following:
There is a dll #1 (Mono.Android.dll):
namespace Xamarin.Android
{
public class Class1
{
}
}
namespace Android.OS
{
public class Class2
{
}
}
There is a dll #2 (Xamarin.Auth.Android.dll):
namespace Xamarin.Auth
{
//This does not compile. See the problem description below.
public class User1 : Android.OS.Class2
{
}
}
Intellisense shows the following problem:
Error CS0234 The type or namespace name 'OS' does not exist in the namespace 'Xamarin.Android' (are you missing an assembly reference?)
This can be fixed by changing the latter namespace to something else or by using the global:: identifier:
namespace SomeOtherNamespace
{
//This compiles ok.
public class User1 : Android.OS.Class2
{
}
}
namespace Xamarin.Auth
{
//This compiles ok.
public class User1 : global::Android.OS.Class2
{
}
}
The question is: why does not intellisense give a warning that the Android namespace branch is ambiguous between global::Xamarin.Android and global::Android? What is the good way out of it? Always use global:: namespace identifier?
You can use the global directive to tell the compiler it should evaluate the namespace from the root, else it tries to evaluate the namespace relative from the current namespace. Using global always uses the full qualified namespace name, so that is why it works when you prefix it.
Another option would be using an alias:
using AOS = Android.OS;
namespace Xamarin
{
public class User1 : AOS.Class2
{
}
}
I am working through the book Professional ASP.NET MVC 2 and I am trying to get the unit testing in chapter 1 to work correctly; howver, I am getting some very strange errors.
There are two projects in the solution: NerdDinner, and NerdDinner.Tests.
In the NerdDinner Project I have the following interface:
IDinnerRepository.cs
//...
namespace NerdDinner.Models
{
interface IDinnerRepository
{
//...
}
}
Also in the NerdDinner project, I have the following class:
//...
using NerdDinner.Models;
//...
namespace NerdDinner.Controllers
{
public class DinnersController : Controller
{
IDinnerRepository dinnerRepository;
// Default constructor
public DinnersController() : this(new DinnerRepository()){} // DinnerRepository is another concrete implementation of IDinnerRepository
//Test constructor
public DinnersController(IDinnerRepository repository) {
dinnerRepository = repository;
}
}
}
In the NerdDinner.Tests project, I have the following concrete implementation of IDinnerRepository:
//...
using NerdDinner.Models;
//...
namespace NerdDinner.Tests.Fakes
{
class FakeDinnerRepository : IDinnerRepository
{
//...
public FakeDinnerRepository(List<Dinner> dinners)
{
//...
}
//...
}
}
Now for the actual unit test (in NerdDinner.Tests)
using NerdDinner.Controllers;
//...
using NerdDinner.Models;
using NerdDinner.Tests.Fakes;
namespace NerdDinner.Tests
{
[TestClass]
public class DinnersControllerTest
{
List<Dinner> CreateTestDinners()
{
//...
}
DinnersController CreateDinnersController()
{
return new DinnersController(new FakeDinnerRepository(CreateTestDinners()));
}
}
}
And now for the actual problem:
In the method CreateDinnersController in the class DinnerControllerClass, I am getting the following error:
DinnersController.DinnersController(NerdDinner.Models.IDinnerRepository repository) (+ 1 overload(s))
Error:
The best overloaded method match for 'NerdDinner.Controllers.DinnersController.DinnersController(NerdDinner.Models.IDinnerRepository)' has some invalid arguments.
It gives me the option to create a constructor stub in DinnersController. It generates the following code:
private global::NerdDinner.Tests.Fakes.FakeDinnerRepository repository;
//...
public DinnersController(global::NerdDinner.Tests.Fakes.FakeDinnerRepository repository)
{
// TODO: Complete member initialization
this.repository = repository;
}
Even after generating that code, I still get the same error. But why should I even need that code anyway? As far as I can tell, I am doing everything correctly.
Can anybody help me figure out what is going on here?
Edit
The generated code is giving the following error:
The type or namespace 'Tests' does not exist in the namespace 'NerdDinner' (are you missing any assembly reference?)
From what you've shown the IDinnerRepository interface is not public meaning that it is not visible from your unit test. I would recommend you making it public as I suspect you have two different interfaces : one defined in the unit test and one in your project which conflict. Also I would recommend you to avoid relying on Visual Studio generate all the crap reflection code in order to test private and internal members.
The last error you're getting is due to there being no reference from the production code to the test code - but that's appropriate. You don't want that extra constructor.
Instead, you need to find out why the existing constructor taking an IDinnerRepository isn't being used. Are you sure you only have one interface called IDinnerRepository? If you go to the FakeDinnerRepository source, go to the declaration, put the cursor in IDinnerRepository and hit F12 (go to definition) does it go to the right place?
If you add a new member to IDinnerRepository (just for the sake of testing: void Foo(); would be fine) does it cause both the production and fake implementation to fail to compile?