I'm sure this is an easy fix and I just can't find it, but here goes:
I have a C# class (let's call it Test) in an assembly (let's say SOTest.dll).
Here is something along the lines of what I'm doing:
private List<string> items;
public List<string> list_items()
{
return this.items;
}
public void set_items(List<string> new_items)
{
this.items = new_items;
}
In the IronRuby interpreter I run:
>>> require "SOTest.dll"
true
>>> include TestNamespace
Object
>>> myClass = Test.new
TestNamespace.Test
>>> myClass.list_items()
['Apples', 'Oranges', 'Pears']
>>> myClass.set_items ['Peaches', 'Plums']
TypeError: can't convert Array into System::Collections::Generic::List(string)
I get a similar error whether I make the argument a 'List< string >', 'List< object >' or 'string[ ]'.
What is the proper syntax? I can't find a documented mapping of types anywhere (because it's likely too complicated to define in certain scenarios given what Ruby can do).
EDIT:
It doesn't look like what I was trying to do is possible. I'll have to include the IronRuby assembly in the .NET project so the input can be an IronRuby type to keep the scripting interface cleaner.
If anybody comes up with a way to make it work how I originally wanted, I'll change the accepted answer.
You will have to construct the list a bit differently:
ls = System::Collections::Generic::List.of(String).new
ls.add("Peaches")
ls.add "Pulms"
Never used it, but I'm guessing something like:
myClass.set_items(System::Collections::Generic::List(string).new ['Peaches', 'Plums'])
That is, construct a List<string> from the array. I'm doubtful of the System::Collections::Generic::List(string) part, but judging from the error message, that's how to give the fully qualified name of a List<string> in IronRuby.
Related
I have a huge code base and I recently made a change where I changed the type of a parameter from String to a custom class. On the next compile I got all the areas where the impact was, but areas where the input type was of type Object failed. for e.g.
String str = "32"
int i = Convert.ToInt32(str)
Now I have changed String to a new custom type lets say MyCustomClass I would now want following code to fail on next compile
MyCustomClass str = new MyCustomClass("32")
int i = Convert.ToInt32(str)
but it won't as Convert.ToInt32 also accepts type Object. Is there some way I can make a change in MyCustomClass that it's not considered Object anymore.
Please note: Convert.ToInt32 is only used for sample I have many more such functions, so please focus your suggestion/answer to question asked.
Override ToString() and IConvertible
You said in the comments that your intentions are to find places where your object, which had previously been treated as a string, and are now being treated as an object.
In these situations typically, the third-party code would call .ToString() on your object to get something which it can use.
So, Convert.ToInt32(str) is equivalent to Convert.ToInt32(str.ToString()).
If you implement ToString() and IConvertible to return whatever your old version of str looked like then it should continue to work in the same way as the old version.
Probably.
Sorry I know that is not the 100% perfect compile time answer you were looking for, but I think you also know very well that your MyCustomClass will always be considered object.
Possible compile time answer:
Write a tool which uses reflection to iterate over every class/struct/interface in every system/third-party DLL.
Output a load of CS files which contain all these same classes, but just throw NotImplementedException.
(T4 could help you do this)
Compile these classes into dummy.dll
Your .csproj now references only this one dummy.dll, instead of the real dlls.
Your project should compile fine against the dummy dll.
Look at your dummy.cs files and delete any use of object.
Re-compile... and suddenly you get a load of compile time errors showing you anywhere you are using an object.
Impliment an implicit cast from MyCustomClass to String.
public static implicit operator string(MyCustomClass str)
{
return "Legacy respresentation of str";
}
This allows the complier the choice of choosing ToInt32(Object) or ToInt32(String), and I bet it favours the later.
This way all your existing function calls will remain the same so you wont have to be concerned about third party implentation details.
(Sorry, I am not at a computer right now so I can`t test that my assumtion is correct. If you do test this, be sure to consider extension methods, as they can affect the conpilers desision making in unexpected ways)
That's a pretty elementary question, but I have never delved into generics before and I found myself in the need to use it. Unfortunately I don't have the time right now to go through any tutorials and the answers I found to related questions so far aren't what one could call basic, so there we go:
Let's say I have the following:
List<MyClass1> list1 = getListType1();
List<MyClass2> list2 = getListType2();
if (someCondition)
MyMethod(list1);
else
MyMethod(list2);
And of course
void MyMethod(List<T> list){
//Do stuff
}
Well, I thought it would be this simple, but apparently it is not. VS warns me that
The type arguments for method MyMethod(System.Collections.Generic.List) cannot be inferred from the usage
and if I compile it anyway, I get a
The type or namespace name 'T' could not be found
error.
In the many answers I found, I read that I have to declare what T is, which makes sense, but I couldn't quite grasp how to do so in such a simplistic scenario. Of course, those answers created even more questions in my mind, but right now I just want an explanation of what I'm doing wrong (besides not studying generics) and how to make it right.
You need to declare T against the method, then C# can identify the type the method is receiving. Try this:
void MyMethod<T>(List<T> list){
//Do stuff
}
Then call it by doing:
if (someCondition)
MyMethod(list1);
else
MyMethod(list2);
You can make it even stricter, if all classes you are going to pass to the method share a common base class:
void MyMethod<T>(List<T> list) where T : MyClassBase
You need to add the generic type parameter for T to your method:
void MyMethod<T>(List<T> list) {
The compiler doesn't know what T represents, otherwise.
You need to let c# know what type is sent:
List<MyClass1> list1 = getListType1();
List<MyClass2> list2 = getListType2();
if (someCondition)
MyMethod<MyClass1>(list1);
else
MyMethod<MyClass2>(list2);
void MyMethod<T>(List<T> list){
//Do stuff
}
Basically, In C#, List < T > class represents a strongly typed list of objects that can be accessed by index.
And it also supports storing values of a specific type without casting to or from object.
we can use in Interger value & String Value in the List.
I have a C# dll exposed to vb6 via com-interop. This is all working, but I am noticing something strange when I pass an array of a custom objects from .Net into VB6.
Accessing the array from VB6 is what baffles me. If I access the array directly I have to do it like this:
Dim manager as New ObjectManager
'Access with two sets of parentheses:
msgbox manager.ReturnArrayOfObjects()(0).Name
However, if I copy the array first I can access it how I would normally expect to:
Dim manager as New ObjectManager
Dim objectArray() As CustomObject
'copy the array
objectArray = manager.ReturnArrayOfObjects
'access normally:
msgbox objectArray(0).Name
In the first case I had to use two sets of parentheses: manager.ReturnArrayOfObjects()(0).Name In the second case I could just use one set of parentheses: objectArray(0).Name
Does anyone know why this is the case? Am I doing something wrong here with the interop maybe?
Here is a quick stub/sample of the C# interop code.
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("[Guid here...]")]
public interface IObjectManager
{
[DispId(1)]
CustomObject[] ReturnArrayOfObjects();
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("[guid here...]")]
public class ObjectManager: IObjectManager
{
public CustomObject[] ReturnArrayOfObjects()
{
return new CustomObject[] { new CustomObject(), new CustomObject() };
}
}
The class CustomObject() is also exposed to com-interop and working just fine. Please let me know if you need me to post anymore code, but I think these little snippets represent the problem well enough to begin with.
Thanks in advance for your help.
ReturnArrayOfObjects() in the C# code is a method. Your VB6 code is invoking the method, which returns the array, and then accessing the first element. The difference between this
msgbox manager.ReturnArrayOfObjects()(0).Name
and this
objectArray = manager.ReturnArrayOfObjects
msgbox objectArray(0).Name
Is that in the second, you invoke the method by itself without accessing the first element, and VB is allowing you to leave off the parentheses from the method call. Conversely, the language is not allowing you to leave off the parentheses when you directly access the first element. It's simply a language feature, it's not a "double parentheses array syntax" issue.
ReturnArrayOfObjects is a method, that must be called. In VB6, if you're calling a method and supplying no parameters, and it's the entire statement, then you can omit the parenthesis.
However, in your first example, you're calling the method, and then indexing into the array returned by that method. You need the first set of parenthesis to indicate that you're passing no parameters to the method, and then the second set of parenthesis are being used for array indexing.
My question is about whether what follows is an appropriate use of the dynamic keyword in C# 4.
I have some helper methods that provide a more useful representation of various objects than their standard ToString methods do, which I use for unit testing. Here is a simplified example:
public static string PrettyPrint<T>(IEnumerable<T> list)
{
return string.Join(", ", list);
}
// Needed because string is IEnumerable<char>, to prevent
// "Hello" -> "H, e, l, l, o"
public static string PrettyPrint(string s)
{
return s;
}
public static string PrettyPrint(object o)
{
return o.ToString();
}
I use them something like this:
public static void PrettyPrinting()
{
object[] things = { 1, "Hello", new int[] {1, 2, 3} };
foreach (dynamic item in things)
{
Console.WriteLine(PrettyPrint(item));
}
}
This produces the following output:
1
Hello
1, 2, 3
Notice that if I replace the dynamic keyword with object, I get the following (all the calls are routed through PrettyPrint(object)), which is what I am trying to avoid:
1
Hello
System.Int32[]
So my question is essentially is this a code smell or is it legitimate to cast an object to dynamic in this way?
So long as you don't abuse it, duck typing like this is part of the reason dynamic was added to the language.
As to your question, I'm not 100% sure as I don't know your teams style of coding. (I also see little comments ;) )
DuckTyping has it's uses - however a developer needs to know what they're doing before using it. Otherwise it's like running with scissors; it could be abused like other keywords in the C# system.
Personally, I'd rather see extension methods, but depending on the developer, his/her arguments and the documentation done I'd probably allow it.
The biggest reason for my hesitation (and this example is pretty tame to some of the ones I've seen online) is it stops you from finding issues at compile time. It requires more QA testing, a lot more boundary testing, and has a higher risk of failure.
Not an answer to the exact question, but I would say your code is not very OO, which is another smell.
Ideally you want to call item.PrettyPrint() and each item is supposed to return its representation, and override PrettyPrint.
Luckily, existing types can be extended with extension methods. They enable you to add the methods and that's what I would do instead.
If you still want to have the logic for the display of each type in one class, I would combine extension methods with the visitor pattern.
That said, I don't have C# environment so I can't test what I propose. Let me know if you try this, and if it works.
This question already has answers here:
Closed 14 years ago.
Duplicate: Function overloading by return type?
Maybe this is a very silly question but I don't understand why I can't declare two methods that have the same signature when they have different return types.
public class MyClass
{
private double d = 0;
public double MyMethod()
{
return d;
}
public string MyMethod()
{
return d.ToString();
}
}
I get a compile error that states that the class already defines a member with the same parameter types.
(Obviously the way I'm using this in my code isn't as simple as my example code...but I think it gets the idea across.)
Am I missing something concerning OO design that makes what I'm trying to do an OOP anti-pattern? Surely the compiler should be able to determine which method I'm trying to use as long as I specifically tell it which one I want.
Given MyClass myClass = new MyClass(); I would expect the following code to work:
double d = myClass.MyMethod();
string s = myClass.MyMethod();
I would expect the following code to have problems:
var v = myClass.MyMethod();
But even in the case of var it should result in a compile error.
Can anyone see what I'm doing wrong here? I'm more than happy to be corrected. :-)
It's because of type coercion.
Say you have the following functions:
int x(double);
float x(double);
double y = x(1.0);
Now, which of the two prototypes should you call, especially if they do two totally different things?
Basically, a decision was made early on in the language design to only use the function name and arguments to decide which actual function gets called, and we're stuck with that until a new standard arrives.
Now, you've tagged your question C# but I see nothing wrong with designing a language that can do what you suggest. One possibility would be to flag as an error any ambiguous commands like above and force the user to specify which should be called, such as with casting:
int x(double);
float x(double);
double y = (float)(x(1.0)); // overload casting
double y = float:x(1.0); // or use new syntax (looks nicer, IMNSHO)
This could allow the compiler to choose the right version. This would even work for some issues that other answers have raised. You could turn the ambiguous:
System.out.Println(myClass.MyMethod());
into the specific:
System.out.Println(string:myClass.MyMethod());
This may be possible to get added to C# if it's not too far into a standards process (and Microsoft will listen) but I don't think much of your chances getting it added to C or C++ without an awfully large amount of effort. Maybe doing it as an extension to gcc would be easier.
There's nothing from stopping you from calling your method without "capturing" the return type. There's nothing from stopping you from doing this:
myClass.MyMethod();
How will the compiler know which one to call in that case?
Edit: Adding to that, in C# 3.0, when you can use var, how will the compiler know which method you're calling when you do this:
var result = myClass.MyMethod();
Because the return type isn't all that important when calling a method. It would lead to ambiguity in many cases to have methods only differing by return type. You might not store the result in a variable at all, or do something like this:
System.out.Println(myClass.MyMethod());
The compiler would have no way to figure out, which of the methods you wanted to call.
A method signature is the name and input parameters (type & order) only. The return type is not part of the signature. Thus two methods with the same name and input parameters are identical and conflict with each other.
What, if any, variable you're assigning the method to can't inform the compiler which method to use. Imagine:
String message = "Result = " + myClass.MyMethod();