In MonoTouch I need to process each object in an NSSet. My attempt, using Enumerate, is as follows:
public override void ReturnResults ( BarcodePickerController picker, NSSet results )
{
var n = results.Count; // Debugging - value is 3
results.Enumerate( delegate( NSObject obj, ref bool stop )
{
var foundCode = ( obj as BarcodeResult ); // Executed only once, not 3 times
if ( foundCode != null )
{
controller.BarcodeScannedResult (foundCode);
}
});
// Etc
}
Although the method is invoked with three objects in results, only one object is processed in the delegate. I would have expected the delegate to be executed three times, but I must have the wrong idea of how it works.
Unable to find any documentation or examples. Any suggestion much appreciated.
You have to set the ref parameter to false. This instructs the handler to continue enumerating:
if ( foundCode != null )
{
controller.BarcodeScannedResult (foundCode);
stop = false; // inside the null check
}
Here is the ObjC equivalent from Apple documentation.
Or you could try this extension method to make it easier..
public static class MyExtensions {
public static IEnumerable<T> ItemsAs<T>(this NSSet set) where T : NSObject {
List<T> res = new List<T>();
set.Enumerate( delegate( NSObject obj, ref bool stop ) {
T item = (T)( obj ); // Executed only once, not 3 times
if ( item != null ) {
res.Add (item);
stop = false; // inside the null check
}
});
return res;
}
}
Then you can do something like:
foreach(BarcodeResult foundCode in results.ItemsAs<BarcodeResult>()) {
controller.BarcodeScannedResult (foundCode);
}
Note: Keep in mind this creates another list and copies everything to it, which is less efficient. I did this because "yield return" isn't allowed in anonymous methods, and the alternative ways I could think of to make it a real enumerator without the copy were much much more code. Most of the sets I deal with are tiny so this doesn't matter, but if you have a big set this isn't ideal.
Related
For example, consider the following C# code:
interface IBase { void f(int); }
interface IDerived : IBase { /* inherits f from IBase */ }
...
void SomeFunction()
{
IDerived o = ...;
o.f(5);
}
I know how to get a MethodDefinition object corresponding to SomeFunction.
I can then loop through MethodDefinition.Instructions:
var methodDef = GetMethodDefinitionOfSomeFunction();
foreach (var instruction in methodDef.Body.Instructions)
{
switch (instruction.Operand)
{
case MethodReference mr:
...
break;
}
yield return memberRef;
}
And this way I can find out that the method SomeFunction calls the function IBase.f
Now I would like to know the declared type of the object on which the function f is called, i.e. the declared type of o.
Inspecting mr.DeclaringType does not help, because it returns IBase.
This is what I have so far:
TypeReference typeRef = null;
if (instruction.OpCode == OpCodes.Callvirt)
{
// Identify the type of the object on which the call is being made.
var objInstruction = instruction;
if (instruction.Previous.OpCode == OpCodes.Tail)
{
objInstruction = instruction.Previous;
}
for (int i = mr.Parameters.Count; i >= 0; --i)
{
objInstruction = objInstruction.Previous;
}
if (objInstruction.OpCode == OpCodes.Ldloc_0 ||
objInstruction.OpCode == OpCodes.Ldloc_1 ||
objInstruction.OpCode == OpCodes.Ldloc_2 ||
objInstruction.OpCode == OpCodes.Ldloc_3)
{
var localIndex = objInstruction.OpCode.Op2 - OpCodes.Ldloc_0.Op2;
typeRef = locals[localIndex].VariableType;
}
else
{
switch (objInstruction.Operand)
{
case FieldDefinition fd:
typeRef = fd.DeclaringType;
break;
case VariableDefinition vd:
typeRef = vd.VariableType;
break;
}
}
}
where locals is methodDef.Body.Variables
But this is, of course, not enough, because the arguments to a function can be calls to other functions, like in f(g("hello")). It looks like the case above where I inspect previous instructions must repeat the actions of the virtual machine when it actually executes the code. I do not execute it, of course, but I need to recognize function calls and replace them and their arguments with their respective returns (even if placeholders). It looks like a major pain.
Is there a simpler way? Maybe there is something built-in already?
I am not aware of an easy way to achieve this.
The "easiest" way I can think of is to walk the stack and find where the reference used as the target of the call is pushed.
Basically, starting from the call instruction go back one instruction at a time taking into account how each one affects the stack; this way you can find the exact instruction that pushes the reference used as the target of the call (a long time ago I wrote something like that; you can use the code at https://github.com/lytico/db4o/blob/master/db4o.net/Db4oTool/Db4oTool/Core/StackAnalyzer.cs as inspiration).
You'll need also to consider scenarios in which the pushed reference is produced through a method/property; for example, SomeFunction().f(5). In this case you may need to evaluate that method to find out the actual type returned.
Keep in mind that you'll need to handle a lot of different cases; for example, imagine the code bellow:
class Utils
{
public static T Instantiate<T>() where T : new() => new T();
}
class SomeType
{
public void F(int i) {}
}
class Usage
{
static void Main()
{
var o = Utils.Instantiate<SomeType>();
o.F(1);
}
}
while walking the stack you'll find that o is the target of the method call; then you'll evaluate Instantiate<T>() method and will find that it returns new T() and knowing that T is SomeType in this case, that is the type you're looking for.
So the answer of Vagaus helped me come up with a working implementation.
I published it on github - https://github.com/MarkKharitonov/MonoCecilExtensions
Included many unit tests, but I am sure I missed some cases.
I've got a GUI with a TabControl. Each new TabPage is created via a new Thread. I want to call this->tabControl->TabCount, but the tabControl is owned by a thread other than the one I'm calling from. Therefore, I need to Invoke a delegate. However, all the examples I find online show printing to std::cout from each of the delegate methods. I need a return value, in this case an int.
delegate int MyDel();
int InvokeTabCount()
{
if (this->InvokeRequired)
{
MyDel^ del = gcnew MyDel(this, &MyTabControl::InvokeTabCount);
auto temp = this->Invoke(del); // can't just "return this->Invoke(del)"
return temp; // Invoke() returns a System::Object^
}
else
{
return this->tabControl->TabCount;
}
}
void CreateNewTab()
{
// do stuff
this->tabControl->TabPages->Insert(InvokeTabCount() - 1, myNewTab); // insert a tab
this->tabControl->SelectTab(InvokeTabCount() - 2); // OutOfBounds and tabPageNew
}
System::Void MethodToAddNewTabPage() //actually a click event but whatever
{
System::Threading::Thread^ newThread =
gcnew System::Threading::Thread(
gcnew System::Threading::ThreadStart(this, &MyTabControl::CreateNewTab));
newThread->Start();
}
Currently, my InvokeTabCount() method is returning -1 when I simply this->Invoke(del) without returning it. And I am unable to return it because my method expects to return an int instead of a System::Object^ which is what Invoke() returns. However, when debugging I find that auto temp contains the value 2 which is correct. And temp->ToString() contains the value "2" which would also be correct.
How do I return this->Invoke(del)?
Do I need to set the value of a global variable from within my InvokeTabCount() method? I suppose I could find a way to translate from System::String^ to std::string to utilize std::stoi(), but that seems like an odd workaround.
Current solution:
delegate int MyDel();
int InvokeTabCount()
{
if (this->InvokeRequired)
{
MyDel^ del = gcnew MyDel(this, &MyTabControl::InvokeTabCount);
auto temp = this->Invoke(del);
return int::Parse(temp->ToString());
}
else
{
return this->tabControl->TabCount;
}
}
The result is an integer, boxed and contained in an Object^ reference. You should be able to simply cast it to int.
If you want to be extra safe, do a null check and verify that temp->GetType() returns int::typeid, but that's probably overkill since you're creating the delegate (still in the typed form) right there.
I'm trying to filter some records using the RecordFilter interface. In my app I have a couple of interfaces similar to this one, on which the user can enter an ID or Name (he/she could enter both or neither of them too)
Here's what I've done so far:
The Customer filter.
Here if the user didn't enter an ID, I pass 0 as a default value, that's why I evaluate customerID!=0
public class CustomerFilter implements RecordFilter {
private String mName_Filter;
private int mID_Filter;
public CustomerFilter(String name_Filter, int id_Filter) {
this.mName_Filter = name_Filter.toLowerCase();
this.mID_Filter = id_Filter;
}
public boolean matches(byte[] candidate) {
try {
ByteArrayInputStream bis = new ByteArrayInputStream(candidate);
DataInputStream dis = new DataInputStream(bis);
int customerID = dis.readInt();
String customerName = dis.readUTF().toLowerCase();
if ((customerName != null && customerName.indexOf(mName_Filter) != -1) && (customerID != 0 && customerID == mID_Filter))
return true;
if (customerName != null && customerName.indexOf(mName_Filter) != -1 && customerID == 0)
return true;
if (customerName == null && (customerID != 0 && customerID == mID_Filter))
return true;
if (customerName == null && customerID == 0)
return true;
} catch (IOException ex) {
//What's the point in catching a exception here???
}
return false;
}
}
The search method:
Note: This method is in a class that I call "RMSCustomer", in which I deal with everything related to RMS access. The search method receives two parameters (id and name) and uses them to instantiate the filter.
public Customer[] search(int id, String name) throws RecordStoreException, IOException {
RecordStore rs = null;
RecordEnumeration recEnum = null;
Customer[] customerList = null;
try {
rs = RecordStore.openRecordStore(mRecordStoreName, true);
if (rs.getNumRecords() > 0) {
CustomerFilter filter = new CustomerFilter(name, id);
try {
recEnum = rs.enumerateRecords(filter, null, false);
if (recEnum.numRecords() > 0) {
customerList = new Customer[recEnum.numRecords()];
int counter = 0;
while (recEnum.hasNextElement()) {
Customer cust;
int idRecord = recEnum.nextRecordId();
byte[] filterRecord = rs.getRecord(idRecord);
cust = parseRecord(filterRecord);
cust.idRecord = idRecord;
customerList[counter] = cust;
counter++;
}
}
else{
customerList = new Customer[0];
//How to send a message to the midlet from here
//saying something like "No Record Exists.Please select another filter"
}
} finally {
recEnum.destroy();
}
}
else{
//How to send a message to the midlet from here
//saying something like "No Record Exists.Please Add record"
}
} finally {
rs.closeRecordStore();
}
return customerList;
}
Even though, the code shown above works I still have some questions/problems:
In the Filter :
1) How can I improve the code that evaluates the possible values of the filters (name,id)? What if I had more filters?? Will I have to test all the possible combinations??
2) If the user doesn’t enter neither a ID nor a name, should I display all the records or should I display a message "Please enter a name or ID"?? What would you do in this case?
3) Why do I have to put a try-catch in the filter when I can't do anything there?? I can't show any alert from there or can I?
In the search method:
1) How can I show a proper message to the user from that method? something like "No records" (see the "ELSE" parts in my code
Sorry If I asked too many questions, it's just that there's any complete example of filters.
Thanks in advance
How can I improve the code that evaluates the possible values of the
filters (name,id)?
The ID is the first field in the record and the fastest one to search for. If the Id matches, It doesn't really matter what the customer name is. Normally you'll be looking for the records where the ID matches OR the customer name matches, so once the ID matches you can return true. This is my proposal for the CustomerFilter class:
public class CustomerFilter implements RecordFilter {
private String mName_Filter;
//Use Integer instead of int.
//This way we can use null instead of zero if the user didn't type an ID.
//This allows us to store IDs with values like 0, -1, etc.
//It is a bit less memory efficient,
//but you are not creating hundreds of filters, are you? (If you are, don't).
private Integer mID_Filter;
public CustomerFilter(String name_Filter, Integer id_Filter) {
this.mName_Filter = normalizeString(mName_Filter);
this.mID_Filter = id_Filter;
}
//You should move this function to an StringUtils class and make it public.
//Other filters might need it in the future.
private static String normalizeString(final String s){
if(s != null){
//Warning: you might want to replace accentuated chars as well.
return s.toLowerCase();
}
return null;
}
public boolean matches(byte[] candidate) {
ByteArrayInputStream bis = new ByteArrayInputStream(candidate);
DataInputStream dis = new DataInputStream(bis);
try {
if(mID_Filter != null){
//If the ID is unique, and the search is ID OR other fields, this is fine
int customerID = dis.readInt();
if(mID_Filter.intValue == customerID){
return true;
} else {
return false;
}
}
if(mName_Filter != null){
String customerName = normalizeString(dis.readUTF());
if(customerName != null && customerName.indexOf(mName_Filter) != -1){
return true;
}
}
if(mID_Filter == null && mName_Filter == null){
return true; // No filtering, every record matches.
}
} catch (IOException ex) {
//Never swallow exceptions.
//Even if you are using an underlying ByteArrayInputStream, an exception
//can still be thrown when reading from DataInputStream if you try to read
//fields that do not exists.
//But even if no exceptions were ever thrown, never swallow exceptions :)
System.err.println(ex);
//Optional: throw ex;
} finally {
//Always close streams.
if(bis != null){
try {
bis.close();
} catch(IOException ioe){
System.err.println(ioe);
}
}
if(dis != null){
try {
dis.close();
} catch(IOException ioe){
System.err.println(ioe);
}
}
}
return false;
}
}
What if I had more filters?? Will I have to test all the possible
combinations??
It depends on your project. Usually the ID is unique and no two records exist with the same id. In this case you should explicitly design the screen so that the user understands that either he types an Id, or else he fills in the other fields. The condition would be like this:
idMatches OR (field1Matches AND field2Matches AND ... fieldNMatches)
If the user types nothing, then all records will be returned.
But then again this is more a UX issue, I don't know if it is valid for your requirements.
From the programming point of view, what is clear is that the more fields you add, the more messy your filter will became. To prevent this, you could use patterns like Decorator, Composite, and even Chain of responsibility. You'll probably have to trade good design for performance though.
If the user doesn’t enter neither a ID nor a name, should I display
all the records or should I display a message "Please enter a name or
ID"?? What would you do in this case?
It depends. Is there any other way to view all records? If so, then show the message.
Why do I have to put a try-catch in the filter when I can't do
anything there?? I can't show any alert from there or can I?
You shouldn't. This class is only responsible of filtering, not of interacting with the user. You can still log the error from the catch clause, and then throw the exception again. That will propagate the exception up to RMSCustomer.search, so whatever client code is calling that function will handle the exception in the same way you are handling the other ones thrown by that method. But keep the finally clause to close the streams.
How can I show a proper message to the user from that method?
something like "No records" (see the "ELSE" parts in my code)
You shouldn't do anything related to the GUI (like showing dialogs) from the RMSCustomer class. Even if you are not using the Model-View-Controller pattern, you still want to keep your class focused on a single responsibility (managing records). This is called the Single responsibility principle.
Keeping your class isolated from the GUI will allow you to test it and reuse it in environments without GUI.
The no records case should be handled by the screen when there are zero results. An array of lenght == 0 is fine here, and the screen will show the "No results" message. For other kinds of errors, you can extend the Exception class and throw your own custom exceptions, i.e: RecordParsingException, from the RMSCustomer.search method. The screen class will then map the different exceptions to the error message in the language of the user.
I am getting started with Haxe and OpenFl, and have some experience with Javascript and Lua.
It was going pretty well, till I got to a point where I needed a function similar to wait() in Lua, etc, which stops the script until the number of seconds you set is over.
How would I go about doing this?
EDIT: To clarify, I am building to Flash.
Although this is old, I wanted to add another point for reference. The OP mentioned in a comment this was for a game. One method I often use is (and could probably be put in a library):
var timerCount:Float = 0;
var maxTimerCounter:Float = 5;
function update () {
timerCounter += elapsedTime;
if (timerCounter > maxTimerCounter){
onTimerComplete();
timerCount = 0;
}
}
In SYS you are looking for:
static function sleep( seconds : Float ) : Void
Suspend the current execution for the given time (in seconds).
Example: Sys.sleep(.5);
http://haxe.org/api/sys/
Edit: User is porting to flash.
So the suggestion is to use Timer
http://haxe.org/api/haxe/timer
In Timer the suggestion is to use
static function delay( f : Void -> Void, time_ms : Int ) : Timer
Someone on stack overflow has an example that looks like this: haxe.Timer.delay(callback(someFunction,"abc"), 10); located here... Pass arguments to a delayed function with Haxe
For the Flash compile target, the best you can do is use a timer, and something like this setTimeout() function.
This means slicing your function into two - everything before the setTimeout(), and everything after that, which is in a separate function that the timeout can call.
so somethine like, eg:
tooltipTimerId = GlobalTimer.setTimeout(
Tooltip.TOOLTIP_DELAY_MS,
handleTooltipAppear,
tootipParams
);
[...]
class GlobalTimer {
private static var timerList:Array<Timer>;
public static function setTimeout(milliseconds:Int, func:Dynamic, args:Array<Dynamic>=null):Int {
var timer:Timer = new Timer(milliseconds);
var id = addTimer(timer, timerList);
timer.run = function() {
Reflect.callMethod(null, func, args);
clearTimeout(id);
}
return id;
}
private static function addTimer(timer:Timer, arr:Array<Timer>):Int {
for (i in 0...arr.length) {
if (null == arr[i]) {
arr[i] = timer;
return i;
}
}
arr.push(timer);
return arr.length -1;
}
public static function clearTimeout(id:Int) {
var timers:Array<Timer> = GlobalTimer.getInstance().timerList;
try {
timers[id].stop();
timers[id] = null;
} catch(e:Error) {/* Nothing we can do if it fails, really. */}
}
}
I am building an asp.net site in .net framework 4.0, and I am stuck at the method that supposed to call a .cs class and get the query result back here is my method call and method
1: method call form aspx.cs page:
helper cls = new helper();
var query = cls.GetQuery(GroupID,emailCap);
2: Method in helper class:
public IQueryable<VariablesForIQueryble> GetQuery(int incomingGroupID, int incomingEmailCap)
{
var ctx = new some connection_Connection();
ObjectSet<Members1> members = ctx.Members11;
ObjectSet<groupMember> groupMembers = ctx.groupMembers;
var query = from m in members
join gm in groupMembers on m.MemberID equals gm.MemID
where (gm.groupID == incomingGroupID) && (m.EmailCap == incomingEmailCap)
select new VariablesForIQueryble(m.MemberID, m.MemberFirst, m.MemberLast, m.MemberEmail, m.ValidEmail, m.EmailCap);
//select new {m.MemberID, m.MemberFirst, m.MemberLast, m.MemberEmail, m.ValidEmail, m.EmailCap};
return query ;
}
I tried the above code with IEnumerable too without any luck. This is the code for class VariablesForIQueryble:
3:Class it self for taking anonymouse type and cast it to proper types:
public class VariablesForIQueryble
{
private int _emailCap;
public int EmailCap
{
get { return _emailCap; }
set { _emailCap = value; }
}`....................................
4: and a constructor:
public VariablesForIQueryble(int memberID, string memberFirst, string memberLast, string memberEmail, int? validEmail, int? emailCap)
{
this.EmailCap = (int) emailCap;
.........................
}
I can't seem to get the query result back, first it told me anonymous type problem, I made a class after reading this: link text; and now it tells me constructors with parameters not supported. Now I am an intermediate developer, is there an easy solution to this or do I have to take my query back to the .aspx.cs page.
If you want to project to a specific type .NET type like this you will need to force the query to actually happen using either .AsEnumerable() or .ToList() and then use .Select() against linq to objects.
You could leave your original anonymous type in to specify what you want back from the database, then call .ToList() on it and then .Select(...) to reproject.
You can also clean up your code somewhat by using an Entity Association between Groups and Members using a FK association in the database. Then the query becomes a much simpler:
var result = ctx.Members11.Include("Group").Where(m => m.Group.groupID == incomingGroupID && m.EmailCap == incomingEmailCap);
You still have the issue of having to do a select to specify which columns to return and then calling .ToList() to force execution before reprojecting to your new type.
Another alternative is to create a view in your database and import that as an Entity into the Entity Designer.
Used reflection to solve the problem:
A: Query, not using custom made "VariablesForIQueryble" class any more:
//Method in helper class
public IEnumerable GetQuery(int incomingGroupID, int incomingEmailCap)
{
var ctx = new some_Connection();
ObjectSet<Members1> members = ctx.Members11;
ObjectSet<groupMember> groupMembers = ctx.groupMembers;
var query = from m in members
join gm in groupMembers on m.MemberID equals gm.MemID
where ((gm.groupID == incomingGroupID) && (m.EmailCap == incomingEmailCap)) //select m;
select new { m.MemberID, m.MemberFirst, m.MemberLast, m.MemberEmail, m.ValidEmail, m.EmailCap };
//select new VariablesForIQueryble (m.MemberID, m.MemberFirst, m.MemberLast, m.MemberEmail, m.ValidEmail, m.EmailCap);
//List<object> lst = new List<object>();
//foreach (var i in query)
//{
// lst.Add(i.MemberEmail);
//}
//return lst;
//return query.Select(x => new{x.MemberEmail,x.MemberID,x.ValidEmail,x.MemberFirst,x.MemberLast}).ToList();
return query;
}
B:Code to catch objects and conversion of those objects using reflection
helper cls = new helper();
var query = cls.GetQuery(GroupID,emailCap);
if (query != null)
{
foreach (var objRow in query)
{
System.Type type = objRow.GetType();
int memberId = (int)type.GetProperty("MemberID").GetValue(objRow, null);
string memberEmail = (string)type.GetProperty("MemberEmail").GetValue(objRow, null);
}
else
{
something else....
}