Well, here is a problem:
I have a part of .NET code, translated into IronPython. This code refers to other .NET code (don't ask why). C# method takes c#-written interface as parameter, f.e.
public int SomeMethod(ISomeInterface instance)
in IronPython I try to call this method from dll, like this:
someValue = SharpClass.SomeMethod(self.InheritedProperty)
self.InheritedPropertyhas type - implementation of ISomeInterface. Let suppose "SomeInterfaceImpl"
And I got runtime error:
expected ISomeInterface, got SomeInterfaceImpl
How to avoid this? I cannot do cast in python, because of abstract interface.
Related
I have no experience in objective c and am trying to translate a class written in objective c to c#. In the objective C class there is the "__kindof" keyword, such as
- (NSArray<__kindof NSViewController *> *)popToViewController:(__kindof NSViewController *)viewController animated:(BOOL)animated;
I researched about this keyword, and the documentation says that it allows NSViewController's subclass to be passed as parameter or element in the array. So I am wondering if there is a similar thing in C#. If not, are we allowed to just pass subclass of NSViewController as this method's parameter or the NSArray's element?
You are mostly talking about Inheritance by means of inheriting a abstract base class or implementing a Interface. Then you can pass in a sub-class instance in place of base-class.
Something like below:
public interface INSViewController { ... }
public class ChildNSViewController : INSViewController {... }
//Your method definition
public IEnumerable<INSViewController> popToViewController(INSViewController arg) {... }
You can call this method now with child type as parameter
popToViewController(new ChildNSViewController())
So I am wondering if there is a similar thing in C#.
Not as such. Effectively __kindof allows a cast which might fail to be omitted - hopefully because the code has done a test and knows it won't.
For example: if Y is a subclass of X and you have a variable of type X then you can test if it is a Y, cast to Y, and call a Y method. If the variable has type __kindof X then the cast step can be omitted. Objective-C however does not statically enforce the test step, relying on runtime tests to catch any error.
C# 7's pattern matching feature can be used to do something sort-of similar, in that you can test (in an if or switch) if something is of a particular type and bind a name to it as that type - so again avoid casts after the test. Unlike the Objective-C feature the test part is required.
If not, are we allowed to just pass subclass of NSViewController as this method's parameter or the NSArray's element?
Yes. In your C# code you might require casts/is/as uses that are implicit in Objective-C - unless you favour dynamic and run time tests.
HTH
I am trying to use C# library in F# so it would be very much specific case. I using Servicestack with F#. Now, I am trying to wire up class with interface using method
RegisterAutoWiredAs<T,'TAs>()
signature. Here is 'T is having constraint that it has to implement 'TAs. It works fine in C# code.
But F# is having constraint while using interface.
let f:IFoo = Foo() // will give type error
let fi:IFoo - Foo() :> IFoo // will work
Here Foo has implemented IFoo. So, this part is quite different than C# equivalent. Now, above signature is giving type error if I do like this
container.RegisterAutoWiredAs<Foo,IFoo>()
And there is noway to do casting while giving parameter.
Here is line from original project I am trying to run. Everything in this code works other than this part and also sadly other equivalent methods are also failing.
And here is the error I am getting in that project
This expression was expected to have type
'MemoryChatHistory' but here has type
'IChatHistory'
F# does not support implicit interface implementations.
I think you may be able to work around this in this instance by making IChatHistory an abstract class rather than an interface (using [<AbstractClass>] attribute).
EDIT:
Nope, I had a chance to play around with it today. I think it's impossible to call this method directly with those type parameters from F#. See this question
How do I translate a `where T : U` generic type parameter constraint from C# to F#?
for a little more discussion.
You might be able to work around this by using reflection to call the method.
I am using silverlight 4.0 in my application. I have a method in my base class as mentioned below
class BaseClass
{
protected CustomRequest GetCustomRequest(IEnumerable<IRequestType> types)
{
//Some code here...
}
}
In my derived class when I call this method like below I get error
IEnumerable<RequestType> requestTypes = CodeToGetThis();
GetCustomRequest(requestTypes)
Note here that in calling statement the type of requestTypes is a enumerable of derived type of IRequestType.
This works well in desktop applications due to introduction of covariance in c#4.0. But it seems that for silverlight 4.0 it is not done for IEnumerable interface.
So what is the best alternative approach I should use in my silverlight application for this?
I somewhere read that it can be done using method overloading but not sure how to do this.
UPDATE:
One thing I missed in the first draft of the question is, I will have many derived types of IRequestType hence craeating overloaded method for each derived type will be a difficulty for me.
Just cast each item to the interface e.g.
IEnumerable<IRequestType> requestTypes = CodeToGetThis().Select(x => (IRequestType)x);
GetCustomRequest(requestTypes)
You could do something with method overloading and have a method that took your derived/concrete type but you would only end up doing something like the above and calling the original method in the overload.
Consider the following code (C# 4.0):
public class Foo : LambdaExpression { }
This throws the following design-time error:
Foo does not implement inherited abstract member
System.Linq.Expressions.LambdaExpression.Accept(System.Linq.Expressions.Compiler.StackSpiller)
There's absolutely no problem with public class Foo : Expression { } but, out of curiosity and for the sake of learning, I've searched in Google System.Linq.Expressions.LambdaExpression.Accept(System.Linq.Expressions.Compiler.StackSpiller) and guess what: zero results returned (when was the last time you saw that?). Needless to say, I haven't found any documentation on this method anywhere else.
As I said, one can easily inherit from Expression; on the other hand LambdaExpression, while not marked as sealed (Expression<TDelegate> inherits from it), seems to be designed to prevent inheriting from it. Is this actually the case? Does anyone out there know what this method is about?
EDIT (1): More info based on the first answers - If you try to implement Accept, the editor (C# 2010 Express) automatically gives you the following stub:
protected override Expression Accept(System.Linq.Expressions.ExpressionVisitor visitor)
{
return base.Accept(visitor);
}
But you still get the same error. If you try to use a parameter of type StackSpiller directly, the compiler throws a different error: System.Linq.Expressions.Compiler.StackSpiller is inaccessible due to its protection level.
EDIT (2): Based on other answers, inheriting from LambdaExpression is not possible so the question as to whether or not it is recommended becomes irrelevant. I wonder if, in cases like this, the error message should be Foo cannot implement inherited abstract member System.Linq.Expressions.LambdaExpression.Accept(System.Linq.Expressions.Compiler.StackSpiller) because [reasons go here]; the current error message (as some answers prove) seems to tell me that all I need to do is implement Accept (which I can't do).
I just looked at the LambdaExpression class in .NET 3.5 using Reflector and the class has only an internal constructor. When I try your code, I'm getting an error "The type 'System.Linq.Expressions. LambdaExpression' has no constructors defined", so on .NET 3.5 this cannot be done (leaving aside the question whether it would be useful to do it).
In .NET 4.0 it behaves as you described. However, the Accept method is internal and so is the StackSpiller type. This again means that you simply can't do this (although it isn't clear from the compiler error message). It is worth noting that the class still has only internal constructor on .NET 4.0. The compiler only finds another reason why you can't override it (and doesn't worry about that any more).
EDIT: Regarding the StackSpiller type - it is internal, so you don't really need to worry about it. However, it looks that the type comes from DLR, which is a .NET 4.0 component that now handles compilation of lambda expressions (and also C# 4 dynamic). Anyway, DLR is open-source, so here is what a summary comment says about this type:
Expression rewriting to spill the CLR stack into temporary variables
in order to guarantee some properties of code generation, for
example that we always enter try block on empty stack.
This means that it is used to do some pre-processing of lambda expressions when they are compiled using the Compile method. You can get the source code from CodePlex.
The error message means that LambdaExpression itself is an abstract class. You need either supply your body for abstract method Accept, or declare Foo as abstract.
However, list of LambdaExpression members on MSDN doesn't list Accept.
Well, the error basically tells us that LambdaExpression is an abstract class, which means that in order to derive from it, you'd have to implement all abstract members. In this case, the Accept method.
It is neither recomended or allowed. The LambdaExpression type has several internal abstract members and an internal constructor. This prevents you from deriving from it from a different assembly unless their is a friend relationship (which there is not in this case)
I've been trying to sign an assembly and getting this error:
'Utils.Connection' does not implement interface member 'Interfaces.IConnection.BugFactory()'. 'Utils.Connection.BugFactory()' cannot implement 'Interfaces.IConnection.BugFactory()' because it does not have the matching return type of 'ThirdPartyLibrary.BugFactory'.
That error looks like a dirty, dirty lie! In Utils.Connection, I have this method:
public new BugFactory BugFactory()
I don't think the new keyword is the problem because 1) removing it doesn't stop the error and 2) I'm having the same error with another class that implements IConnection that does not use the new keyword. Update: if I use override instead of new, I get this error:
'Utils.Connection.BugFactory()': cannot override because 'ThirdPartyLibrary.ConnectionClass.BugFactory' is not a function
This is because ThirdPartyLibrary.ConnectionClass.BugFactory is a property.
There is only one BugFactory class, so it isn't a problem of the interface requiring a different BugFactory return type than what the method returns. Even if I explicitly mark my method as returning ThirdPartyLibrary.BugFactory, I still get the error when I try to strong-name the Utils DLL.
Could this be the result of ThirdPartyLibrary being an old COM library that is not CLS-compliant? I have no control over this library. When I do not try to sign the Utils assembly, I do not get the interface error.
My big question is: how can I sign this assembly?
Edit: here's what IConnection has:
using ThirdPartyLibrary; // The only using statement
namespace Interfaces
{
public interface IConnection
{
...
BugFactory BugFactory();
}
}
I'm still suspicious of the new keyword for this error.
You say "I don't think the new keyword is the problem because 1) removing it doesn't stop the error", but you must bear in mind that if your method hides a base method, the compiler will add a new, even if you don't specify it, unless you explicity specify override instead.
All the explicit new does is to prevent a compiler warning (not an error).
Is there really a method to hide or override at all?
What happens if you specify virtual instead of new on this method. Does it compile? Does it error with "no suitable method found to override?"
[Edit in response to your comment]
I get this error:
"'Utils.Connection.BugFactory()':
cannot override because
'ThirdPartyLibrary.ConnectionClass.BugFactory'
is not a function." The original
ThirdPartyLibrary.ConnectionClass.BugFactory
is a property.
I suspect this may be the issue. You are overriding a property with a method.
By using the new keyword, you are hiding the old property to anyone that has a reference to your derived class.
By contrast, anyone that has a reference cast as the superclass (the one you are inheriting from), they will see the old property, and not your new method.
Can you give some more code of the superclass (or interface) together with the derived class?
[Edit in response to your comment]
I'm trying to change the interface to
have BugFactory be a property instead
of a method
The trouble with new is that it seems like a bit of magic, that can let you change argument types and return types, but it is really pure evil.
Instead of changing the types for all consumers of the code, it only does it for consumers that are cast as the overriding new type. This gets you in the horrible position where two consumers to the same instance will see different signatures depending on how they are cast.
See if you can identify the consuming code that is complaining, and have a think around whether more of your code needs to change to support the type changes. Also, is there the possibility that you are trying to do something that is "a bit of a nasty hack"?
Namespace/version problems?
ThirdPartyLibrary.BugFactory might be a different type, if you have two different versions of the 3rd party assembly being referenced somehow: One during compile time and a different one when you sign/verify..
It sounds like you are simply referencing the COM library through the Add Reference dialog. You should probably create a Primary Interop Assembly for the COM library which can be signed. One of the caveats of signing an assembly is that all the assemblies it references must also be signed.
You would normally use the SDK program TlbImp:
TlbImp yourcomlibrary.tlb /primary /keyfile:yourkeyfile.snk /out:yourcomlibrary.dll
What does your IConnection interface look like? It seems like your ThirdPartyLibrary has a BugFactory object and you also have a BugFactory object either in your project or another reference. Did you try changing both the interface and the concrete type to explicity use ThirdPartyLibrary.BugFactory as the return type for that method?