I am using Visual Studio 2010 with two projects.
One contains a project referencing Microsoft's Exchange.WebServices dll(ver1.2) for accessing ExchangeServices. I created a class which contains some helper methods and wrappers to carry out various tasks while connected to an Exchange server(through the ExchangeService API). The ExchangeService constructor can accept an enum of ExchangeVersion, to specify the server version info. So I created two constructors within my class.
public class ExchangeConnector(string ver)
{
// Property assignments
}
public class ExchangeConnector(ExchangeVersion ver)
:this(ver.toString()) //Using(or not using) "this", doesn't seem to matter...
{ }
I created the constructor which accepts a string parameter, so that other projects don't necessarily need to add the Exchange.WebServices library.
But then I ran into an un-foreseen issue.
When I create an instance of ExchangeConnector("Exchange2007_SP1") in my second project(that does not contain a reference to the Exchange.WebServices dll), Intellisense doesn't pick the right constructor and doesn't show any pre-compile errors. When I force the build, though, I get the following error:
Error: The type 'Microsoft.Exchange.WebServices.Data.ExchangeVersion' is defined
in an assembly that is not referenced. You must add a reference to assembly
'Microsoft.Exchange.WebServices, Version=14.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35'.
I am not even using the constructor with the ExchangeVersion enum reference, but it requires me to have a reference to it?
If I comment out the constructor with the ExchangeVersion enum, everything compiles, works, no run-time errors.
OR
If I modify the overload constructor so Intellisense can't possibly confuse the two, such as:
public class ExchangeConnector(string url, ExchangeVersion ver)
{
// Property assignments
}
When I call ExchangeConnector("Exchange2007_SP1"), the code compiles and works fine. No runtime errors.
It is almost as though VS can't resolve which constructor to properly use. Now I know I can add the reference to the second project and be done with it, but I am curious as to why VS is doing this. Any ideas?
After inspiration from Scott(the other one) and the link provided by CodeCaster, I think I finally found my answer.
It as part of the C# Language Specification(Visual Studio .Net 2003 Edition).
In Section 10.10 Instance Constructors:
An instance constructor initializer of the form base(argument-listopt) causes an instance constructor from the direct base class to be invoked. That constructor is selected using argument-list and the overload resolution rules of Section 7.4.2. The set of candidate instance constructors consists of all accessible instance constructors contained in the direct base class (including any default constructor, as defined in Section 10.10.4). If this set is empty, or if a single best instance constructor cannot be identified, a compile-time error occurs.
Diving down further to the definition...
In Section 7.4.2 Overload resolution:
Once the candidate function members and the argument list have been identified, the selection of the best function member is the same in all cases:
Given the set of applicable candidate function members, the best function member in that set is located.
If the set contains only one function member, then that function member is the best function member.
Otherwise, the best function member is the one function member that is better than all other function members with respect to the given argument list, provided that each function member is compared to all other function members using the rules in Section 7.4.2.2.
If there is not exactly one function member that is better than all other function members, then the function member invocation is ambiguous and a compile-time error occurs.
And even further...
Section 7.4.2.2 Better function member[3]
[3][http://msdn.microsoft.com/en-us/library/aa691338(v=vs.71).aspx]
Given an argument list A with a set of argument types {A1, A2, ..., AN} and two applicable function members MP and MQ with parameter types {P1, P2, ..., PN} and {Q1, Q2, ..., QN}, MP is defined to be a better function member than MQ if
for each argument, the implicit conversion from AX to PX is not worse than the implicit conversion from AX to QX, and
for at least one argument, the conversion from AX to PX is better than the conversion from AX to QX.
When performing this evaluation, if MP or MQ is applicable in its expanded form, then PX or QX refers to a parameter in the expanded form of the parameter list.
So in summary:
A constructor with the same number of arguments must be evaluated through implicit conversion as to which function member(constructor) would be better.
Hence why I needed to add the reference to the second project so the compiler could determine which constructor was better.
If the constructors don't have the same number of arguments, evaluation doesn't need to occur, and the compiler doesn't need the reference to the second project.
It makes sense to me that if your project is referencing another project with an overloaded constructor where one of those constructors accepts a referenced library, that your calling project would need that reference to compile even though you aren't using that particular constructor. Wouldn't the compiler need that reference to decide which constructor to use? Maybe I'm missing something, but it seems logical to me that it's working correctly.
Related
Some sample code to illustrate what I'm talking about. I've got a utility class with a single method. That method takes one argument: a System.IO.FileInfo object. From the PowerShell side I can pass in a System.String object and everything "just works". I'm curious as a develop getting more into PowerShell this year I'm curious:
What feature of PowerShell allows this to happen?
Is this open to extension / use by any developer in PowerShell 7.x? (non-internal)
C#:
using System.IO;
using System.Linq;
namespace TestProject
{
public class Utility
{
public string GetFirstLine(FileInfo fileInfo)
{
string firstLine = File.ReadLines(fileInfo.FullName).First();
return firstLine;
}
}
}
PowerShell:
Add-Type -Path "C:\assemblies\TestProject.dll"
$util = [TestProject.Utility]::New()
$util.GetFirstLine("C:\temp\random-log.txt")
Note: I realize this is trivial example. Code is meant for quickly illustrating the capability in PowerShell I am interested in.
Although PowerShell is more or less a "real .NET language", it does extend the common type system with an array of behaviors that sometimes conflict with what you know about .NET's type system behavior from languages like C# or VB.NET.
This additional type system layer bolted on top of the CLR is aptly named the Extended Type System (ETS), and it's directly responsible for making argument conversion "just work" the way you've observed.
When the PowerShell runtime reaches a method invocation statement like $util.GetFirstLine("C:\temp\random-log.txt"), it has to pick an appropriate overload, just like the C# compiler does.
The first step is to identity overloads for which the number of arguments passed can cover all mandatory parameters of the given overload signature. In your case, only 1 such signature can be resolved at this step, so PowerShell now has two pieces of the puzzle:
A method stub with the signature string GetFirstLine(FileInfo fileInfo)
An argument value of type [string]
At this point, the C# compiler would give up and report CS1503: Argument 1: cannot convert from 'string' to 'System.IO.FileInfo'.
PowerShell, on the other hand, is designed to be helpful in the hands of system administrators and operators - people who might not put too much thought into data structure design, but who are chiefly concerned with string representations of data (after all, this is what bash, cmd, etc. taught them to use).
To meaningfully convert from a string (or any other non-compliant argument type) at just the right time, ETS comes with a number of facilities and hooks for implicit type conversion that the runtime then attempts, one by one, until it either finds a valid conversion mechanism, or fails (at which point the method invocation fails too):
Built-in converters
These take priority to handle the most common edge cases, like null-conversions, "truthy/falsy"-to-real-[bool] conversions, stringification of scalars, etc. - without these, PowerShell would be a pain in the ass to work with interactively.
Example:
These flow control statements behave exactly like you'd expect thanks to built-in conversions: if($null){ <# unreachable #> }, do{ Stop-Process chrome }while(Get-Process chome)
Custom type converters
These are concrete type converter implementations registered to one or more target types - this can be useful for modifying the binding behavior of complex types you've brought with you into the runtime.
Example:
The RSAT ActiveDirectory module uses type adapters to interchange between the different data types modeling specific directory object classes - allowing you to seamlessly pipe output from Get-ADComputer (very specific output type) to Get-ADObject (generalized output type) and vice versa.
Parse converters
If no appropriate built-in or custom type converter can be found, PowerShell will attempt to resolve a Parse() method with the appropriate return type on the target type.
Example:
The cast operation [timespan]'1.02:15:25' can succeed this way.
Constructor-based conversions
If none of the above works, PowerShell will attempt to resolve a constructor that can be invoked with a single parameter argument of the source type given.
This is what happens in your case - PowerShell effectively excutes $util.GetFirstLine([System.IO.FileInfo]::new("C:\temp\random-log.txt")) for you
CTS conversions
Finally, if all of ETS' conversation attempts fail, it falls back to resolving implicit (and eventually explicit) conversions defined by the types themselves.
Example:
This conversion succeeds because the [DateTimeOffset] type has an implicit conversion operator for [DateTime]: (Get-Date) -as [DateTimeOffset]
The concrete type converters mentioned above will automatically be respected by ETS if they've either been included in a type data file (see about_Types.ps1xml), or if the target type is public and the source definition was decorated with a [TypeConverter()] attribute.
Additionally, you can register new type conversion primitives at runtime with the Update-TypeData cmdlet.
Of course the madness doesn't stop there, there are also additional facilities specifically for converting/transform command arguments, but that's beyond the scope of this question :)
Have have big problem with Visual Studio 2013 and 2015. In one class, i have defined this two methods:
public List<T> LoadData<T>(string connectionStringName = "", string optWherePart = "", params object[] parameter)
public List<T> LoadData<T>(string optWherePart, params object[] parameter)
I only want to call the second method like this:
....LoadData<Config_Info>("ConfigName LIKE 'Version' AND UserName LIKE '' AND PlugInName Like ?", parameter: ProductName);
If i go to definition in Visual Studio 2013, i come to the second method declaration, but in Visual Studio 2015, i come to the first. Both solutions are
absolutly identically.
Even the compiled result is different, so if i compile the same solution with VS 2015, the program stops working.
This is a very strange behaviour.
Does any one has an idea, what the differences are?
This is based on the C# 5 specification, but since the C# 6 specification doesn't appear to have been published yet that's the best I can do. It's also an attempt to invoke Cunningham's Law.
As a preliminary, in the language of s7.5.3.1 ("Applicable Function Member") of the spec, both function members are applicable (either of them could be called if the other didn't exist) in their expanded form (the params object[] can't be fulfilled by the string ProductName so is converted to an object argument).
Thus we move on to s7.5.3.2 ("Better Function Member") in order to decide which of the two is the better function to call.
Firstly, a stripped-down argument list A is constructed containing just the argument expressions themselves in the order they appear in the original argument list:
{ string "ConfigName [...]", string ProductName }
Next, [p]arameter lists for each of the candidate function members are constructed in the following way:
The expanded form is used if the function member was applicable only in the expanded form.
Optional parameters with no corresponding arguments are removed from the parameter list
The parameters are reordered so that they occur at the same position as the corresponding argument in the argument list.
This gives us the following:
{ string connectionStringName, object parameter } (optWherePart removed, params expanded)
{ string optWherePart, object parameter } (params expanded)
We then have a sequence of comparisons to make to decide which of these is the better function member. Calling one Mp and one Mq, these go as follows:
If Mp is a non-generic method and Mq is a generic method, then Mp is better than Mq.
No difference here
Otherwise, if Mp is applicable in its normal form and Mq has a params array and is applicable only in its expanded form, then Mp is better than Mq.
No difference here; both are in their expanded form
Otherwise, if Mp has more declared parameters than Mq, then Mp is better than Mq. This can occur if both methods have params arrays and are applicable only in their expanded forms.
Not 100% on this one. Both our argument lists use 2 of the parameters from the original function definitions. I think this is solely meant to distinguish between one case where both arguments went into the same params array and one where one went into the array and one went into a normal argument.
Otherwise if all parameters of Mp have a corresponding argument whereas default arguments need to be substituted for at least one optional parameter in Mq then Mp is better than Mq.
Aha! Our first argument list is missing optWherePart, which needed a default argument, so the second argument list is better! So VS2015 is wrong!
... but wait. What does this last bullet even mean? Mp and Mq are specifically parameter lists where [o]ptional parameters with no corresponding arguments are removed. There is no way either of them could not have a corresponding argument because if they didn't, they'd have been removed.
In conclusion, I can't tell whether this is a bug in the old compiler, the new compiler... or the C# specification.
I've found a blog post by SLaks that also seems to think the old behaviour was a bug. The blog states that Roslyn had fixed this by making the compiler fail, and that's not what I see any more. Maybe they changed their minds?
Edit: Update! My Roslyn bug report resulted in a change to the compiler to ensure that, in this case, the second overload is picked. This appears to be because of the default arguments need to be substituted wording above. I still think the spec is ambiguous, so I'm disappointed that only a code change was made (and not a spec change, or even a discussion about why the second overload is the better one), but at least the VS2015 runtime beaviour is now the same as it was in VS2013.
I've got a legacy vb.net dll referenced in my c# project.
calling the various methods no problem, but I need to be able to display a form from the dll, so users can pick the right line from a database response.
Assembly assembly = Assembly.LoadFile("FMSValidation.dll");
produces no error, but
Type type = assembly.GetType (FMSValidation.CreditorDetails );
tells me 'CreditorDetails' is a type, which is not valid in the context.
assembly.GetType does not accept an actual type. It accepts a string:
Type type = assembly.GetType("FMSValidation.CreditorDetails");
It wouldn't make sense for assembly.GetType to be able to take a type, since at that point you already have a type.
Once you have a type, you can create an instance of it with the activator class:
var form = (System.Windows.Forms.Form)Activator.CreateInstance(type);
form.ShowDialog();
If CreditorDetails requires any constructor arguments, use an overload of CreateInstance that accepts the array of arguments.
It seems like the compiler knows FMSValidation.CreditorDetails is a type - so I wonder why you are dynamically loading the assembly and trying to use GetType at all. You should just be able to add a reference to the assembly and use its types like you would any other, like new FMSValidation.CreditorDetails().
FMSValidation.CreditorDetails is a type, but it is not an actual Type object. If you want an actual type object, and you can write the name of the type in your source code (ie. it's not in a string variable or something) then you would use typeof(FMSValidation.CreditorDetails) instead of assembly.GetType.
I have referenced a dll in a asp.net 2.0 web site developed in Visual Studio. The person who supplied the dll said to reference it and instantiate a class called Subjects.
I have referenced it and if I type:
Subjects mySubjects = new Subjects();
it appears to be 'found' as 'Subjects' appears in light blue text.
If I then try to access a method by writing this:
string ProjectSubject = mySubjects.GetSubject(ProjectID);
again, it seems to be 'found' in that intellisense, as soon as you type the full stop after mySubjects shows the methods available to be called.
So far, so good. But, when I try to run the page, I get a compile error which is:
No overload for method 'Subjects' takes 0 arguments.
I don't understand. I thought you always had to reference a class with
someClass myClass = new someClass();
No overload for method 'Subjects' takes 0 arguments.
This means that there is no parameterless constructor defined for Subjects. Intellisense should show you the possible options when you type the initial opening parenthesis, otherwise look up the class in object browser to see the possible constructors (there could be more than 1).
It is also possible that there is no public constructor defined on that class, however this is unlikely as the author has told you to "instantiate an instance of Subjects". Again, object browser should tell you what's available.
Apparently the constructor for Subjects takes a parameter.
I obviously don't know if you have any sort of documentation for your assembly or not.
But you should be able to Visual Studio's 'Object Browser' feature to inspect the type, and from there perhaps figure out what type of parameter it takes.
Please, help me to explain the following behavior:
dynamic d = 1;
ISet<dynamic> s = new HashSet<dynamic>();
s.Contains(d);
The code compiles with no errors/warnings, but at the last line I get the following exception:
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'System.Collections.Generic.ISet<object>' does not contain a definition for 'Contains'
at CallSite.Target(Closure , CallSite , ISet`1 , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2[T0,T1](CallSite site, T0 arg0, T1 arg1)
at FormulaToSimulation.Program.Main(String[] args) in
As far as I can tell, this is related to dynamic overload resolution, but the strange things are
(1) If the type of s is HashSet<dynamic>, no exception occurs.
(2) If I use a non-generic interface with a method accepting a dynamic argument, no exception occurs.
Thus, it looks like this problem is related particularly with generic interfaces, but I could not find out what exactly causes the problem.
Is it a bug in the compiler/typesystem, or legitimate behavior?
The answers you have received so far do not explain the behaviour you are seeing. The DLR should find the method ICollection<object>.Contains(object) and call it with the boxed integer as a parameter, even if the static type of the variable is ISet<dynamic> instead of ICollection<dynamic> (because the former derives from the latter).
Therefore, I believe this is a bug and I have reported it to Microsoft Connect. If it turns out that the behaviour is somehow desirable, they will post a comment to that effect there.
Why it compiles: the entire expression is evaluated as dynamic (hover your mouse over it inside your IDE to confirm), which means that it is a runtime check.
Why it bombs: My (completely wrong, see below) guess is that it is because you cannot implement a dynamic interface in such a manner. For example, the compiler does not allow you to create a class that implements ISet<dynamic>, IEnumerable<dynamic>, IList<dynamic>, etc. You get a compile-time error stating "cannot implement a dynamic interface". See Chris Burrows' blog post on this subject.
http://blogs.msdn.com/b/cburrows/archive/2009/02/04/c-dynamic-part-vii.aspx
However, since it's hitting the DLR anyway, you can make s completely dynamic.
dynamic s = new HashSet<dynamic>;
s.Contains(d);
Compiles and runs.
Edit: the second part of this answer is completely wrong. Well, it is correct in that you can't implement such an interface as ISet<dynamic>, but that's not why this blows up.
See Julian's answer below. You can get the following code to compile and run:
ICollection<dynamic> s = new HashSet<dynamic>();
s.Contains(d);
The Contains method is defined on ICollection<T>, not ISet<T>. The CLR doesn't allow an interface base method to be called from a derived interface. You usually doesn't see this with static resolution because the C# compiler is smart enough to emit a call to ICollection<T>.Contains, not the non-existing ISet<T>.Contains.
Edit: The DLR mimics the CLR behavior, that's why you get the exception. Your dynamic call is done on an ISet<T>, not an HashSet<T> the DLR will mimics the CLR: for an interface, only interfaces methods are searched for, not base interfaces (contrary to classes where this behavior is present).
For an in-depth explanation, see a previous response of mine to a similar question:
Strange behaviour when using dynamic types as method parameters
Note that the type dynamic doesn’t actually exist at run-time. Variables of that type are actually compiled into variables of type object, but the compiler turns all the method calls (and properties and everything) that involve such an object (either as the this object or as a parameter) into a call that is resolved dynamically at runtime (using System.Runtime.CompilerServices.CallSiteBinder and related magic).
So what happens in your case is that the compiler:
turns ISet<dynamic> into ISet<object>;
turns HashSet<dynamic> into HashSet<object>, which becomes the actual run-time type of the instance you’re storing in s.
Now if you try to invoke, say,
s.Contains(1);
this actually succeeds without a dynamic invocation: it really just calls ISet<object>.Contains(object) on the boxed integer 1.
But if you try to invoke
s.Contains(d);
where d is dynamic, then the compiler turns the statement into one that determines, at runtime, the correct overload of Contains to call based on the runtime type of d. Perhaps now you can see the problem:
The compiler emits code that definitely searches the type ISet<object>.
That code determines that the dynamic variable has type int at runtime and tries to find a method Contains(int).
ISet<object> does not contain a method Contains(int), hence the exception.
ISet interface does not have a method 'Contains', HashSet does however?
EDIT
What i meant to say was the binder resolves 'Contains' when given the HashSet concreate type, but doesnt find the inherited 'Contains' method in the interface...