I have a utility class that takes a generic list as a parameter.
Code looks like:
Function DoStuff(collection as Object, elt as Object)
...
collection.Add(elt)
...
End Function
This is called with:
DoStuff( List(Of Foo), new Foo() )
DoStuff( List(Of Bar), new Bar() )
There are about a dozen different types.
Currently, passing as Object results in a Late bound resolution warning, although it runs fine.
I've tried different ways to pass in collection and elt (Foo and Bar both extend a base class) but can't seem to figure out the "proper" way to do it.
Ideas?
I think you're looking for something like this.
Public Sub DoStuff(Of T)(collection As List(Of T), elt As T)
...
collection.Add(elt)
...
End Function
The answers by womp and Qua are I think the correct ones, however if your 12 types all inherit from some common base class (as your original question suggests) you can write the method such that it works with your types, and only your types as such:
Public Sub DoStuff(Of T As YourBaseClass)(collection As List(Of T), elt As T)
...
collection.Add(elt)
...
End Sub
This way the method works only for types which inherit from YourBaseClass.
You should always strive to built/use strongly typed code. Imagine what would happen if an integer was passed as the collection object - You would have to manually check for the type of the variable. Even worse though, the user of your method would have to look up in the documentation what kind of object your method required as it's first parameter.
You should go by the approach suggested by womp, or even better you should make your parameter require an object that extends the generic collection interface, ICollection(Of T):
Public Function DoStuff(Of T)(collection As ICollection(Of T), elt As T) As stuff
...
collection.Add(elt)
...
End Function
since this would allow the user of the method to pass not only lists, but also all other classes that inheritage the ICollection(Of T) interface (synchronizedCollection, HashSet, LinkedList, or custom classes ect.) which is really the power of OO programming.
Related
For asp.net framework 4.5 vb
I know that I can use a session variable.. but wondering if there is a more efficient way to return a variable (we call it a condition code) that we set almost in every function /sub being called.
Example
Function xyz(bla as String, blab as String) as dataset
.. do the deed
**Cond.code = -1**
Return ds
We use this Cond.code everywhere. Obviously it can not be a Public Shared variable... but want the most efficient way to always set a "condtion code" within any sub or function... It is valid, only from the time it is set, to the time it is checked by the calling function... so the lifetime is very short.
It's unclear what, exactly the condition code is used for. It's possible that a proper use of custom exception types would replace the need for it. However, if you really need it, it would be better to have it be returned by the method, rather than essentially setting a global, which is pretty rotten. What happens if two methods ever got called simultaneously? It's just brittle and unnecessarily confining.
For instance, you could make a container to hold the return value plus the condition code, like this:
Public Class ReturnValue(Of T)
Public Sub New(value As T, conditionCode As Integer)
Me.Value = value
Me.ConditionCode = conditionCode
End Sub
Public ReadOnly Property Value As T
Public ReadOnly ConditionCode As Integer
End Class
By requiring the code in the constructor, like that, it forces every method to always specify a condition code in its return value. That way it could never be forgotten:
Function xyz(bla As String, blab As String) As ReturnValue(Of DataSet)
' do the deed
Return New ReturnValue(ds, -1)
End Function
However, even then, I would still strongly recommend making the condition code use an enumeration or, at the very least, a set of constants. -1 isn't very self documenting.
I have a Class with a Constructor. My constructor takses all the required parameter, then I use the parameters to return another class.
Public Class SearchResults()
private id as int
Sub New(id) ' Constructor
getResults(id)
End Sub
Public Function getResults(byval id as int) as List(of Products)
........
return list (of products)
End Function
End
Then in my page I want to get all the productts.
Dim s = new SearchResults( 1 )
Dim p as list(of Products) = s.getResults()
----now I can do for Each on this
This works for me, but I do have a feeling there has to be a better way of doing it, I want to stick to the best standards. do you guys think, this is the best approach or it could be improved? My designers will be utilizing this class within their projects...so i would love to make it as simple as possible for them.
or maybe how to create an Collection of a Class...for example Class Product and its collection Class Products, Where Products is the Collection of Project Class.
There are three ways to do what you want:
1) You can load the results and store them in the object on the constructor
2) You can store the ID in the object and call the function to get the results when needed
3) You can make the function static and pass in the ID as well as the collection (or resource needed to get the collection) and not use an object at all.
Depending on what you need, most likely either 1 or 3 are going to be best. If you plan on reusing the object for other methods than just the one function, then option 1 is the best, but if you just need the 1 function, go with option 3 like this:
Public Class SearchResults
Public Static Function getResults(ByVal id As int) As List(Of Products)
'........
return list (of products)
End Function
End Class
You could make the getResults method static possibly and cut out having to create a class instance to call it.
I personally would declare the getResults method as Shared so that you don't have to create a SearchResults object just to access that method. This would also allow you to call the method again with another ID without having to create another object.
Imagine the following VB.NET class:
Public Class P
Public Function GetDumbList() As List(Of DumbPeople)
Dim retList As New List(Of DumbPeople)
retList.Add Person1
retList.Add Person2
Return retList
End Function
End Class
Now we have the following Classic ASP Page:
<%
Dim P
Set P = Server.CreateObject("Project.Assembly.Namespace.P")
retList = P.GetDumbList()
...
...
...
%>
How do you use retList? I have tried looping through using the 2 following methods:
1. For Each Person in retList
Throws error "Object not a collection"
2. For i = 0 To Ubound(retList)
Throws error "Type mismatch: -UBound-
Thanks in advance for your help.
Jake
UPDATE
Based on help from Chris Haas we were able to solve the issue. It does require a second ASPClassic helper function to convert the List(of T) to an Object array; however, COM objects cannot expose generic methods. Because of this, the input must be a specific type of List to be converted to the Object array. Solution Below
Public Function DumbPeopleListToObjectArray(ByVal DPList As IList(Of DumbPeople)) As Object()
Return Array.ConvertAll(Of DumbPeople, Object)(DPList.ToArray(), New Converter(Of DumbPeople, Object)(Function(j) DirectCast(j, Object)))
End Function
Thank you to Chris Haas for putting me on the right direction.
Hope this helps someone else.
I don't think you're going to be able to use generics with ASP Classic, I think you're going to need to convert it to an array. You could write a utility method for ASP Classic usage that takes a IList(Of T) and returns an Object(). Its an extra step for ASP Classic people to jump through but not the end of the world.
EDIT
Something like this might do the trick:
Public Shared Function ToASPClassicArray(Of T)(ByVal myList As IList(Of T)) As T()
Return myList.ToArray()
End Function
EDIT 2
Here's another version that returns just an object, pretty ugly but should still work.
Public Shared Function ToASPClassicArray(Of T)(ByVal myList As IList(Of T)) As Object()
Return Array.ConvertAll(Of T, Object)(myList.ToArray(), New Converter(Of T, Object)(Function(j) DirectCast(j, Object)))
End Function
It's too complicate to explain but I'll give you an example
I have an AS3 ResultEvent Object
and this object has several propeties which can be accessed by this like:
event.result.name or event.result.age .....
and, I have this String variable: eventProperty:String that contains "name" or "age"
How do I access to event.result. with the variable?
thank you.
The ActionScript (or ECMAScript) . operator is just syntactic sugar, useful but not really needed. For what you want to do you can use the normal object property access operator [].
So you have to do it like this event.result[ eventProperty ].
Good luck,
Alin
You should probably move your ResultEvent object into an actual Object type first. Then you can access the properties via the object. If your object is an arraycollection, make sure to immediately pass the ResultEvent into an arraycollection since you cannot cast it as you normally might (ArrayCollection)ResultEvent. Here is how to throw the result into an object:
var yourObjectName:Object = event.result;
and here is how to throw it into an arraycollection if you need to:
var yourArrayCollection:ArrayCollection = event.result as ArrayCollection;
I'm using Flex 3.3, with hamcrest-as3 used to test for item membership in a list as part of my unit tests:
var myList: IList = new ArrayCollection(['a', 'b', 'c']).list;
assertThat(myList, hasItems('a', 'b', 'c'));
The problem is that apparently the IList class doesn't support for each iteration; for example, with the above list, this will not trace anything:
for each (var i: * in myList) { trace (i); }
However, tracing either an Array or an ArrayCollection containing the same data will work just fine.
What I want to do is (without having to tear apart my existing IList-based interface) be able to treat an IList like an Array or an ArrayCollection for the purposes of testing, because that's what hamcrest does:
override public function matches(collection:Object):Boolean
{
for each (var item:Object in collection)
{
if (_elementMatcher.matches(item))
{
return true;
}
}
return false;
}
Is this simply doomed to failure? As a side note, why would the IList interface not be amenable to iteration this way? That just seems wrong.
You will have to create a custom Matcher that's able to iterate over an IList. More specifically, extend and override the matches method of IsArrayContainingMatcher that you reference above (and you'll probably want to create IList specific versions of hasItem and hasItems as well). A bit of a pain, but perhaps it's worth it to you.
Longer term, you could file an issue with hamcrest-as3 (or fork) to have array iteration abstracted using the Iterator pattern. The right Iterator could then be chosen automatically for the common types (Proxy-subclasses, IList) with perhaps an optional parameter to supply a custom Iterator.
For the main issue: Instead of passing the ArrayCollection.list to assertThat(), pass the ArrayCollection itself. ArrayCollection implements IList and is iterable with for each.
var myList:IList = new ArrayCollection(['a', 'b', 'c']);
assertThat(myList, hasItems('a', 'b', 'c'));
In answer to part two: ArrayCollection.list is an instance of ArrayList which does not extend Proxy and does not implement the required methods in order to iterate with for each. ArrayCollection extends ListCollectionView which does extends Proxy and implements the required methods.
HTH.
I find myself coming back to this every once in a while. Rather than writing new Matchers, I find that the easiest solution is always to just call toArray() on the IList and match against the resulting array.