- "is"-operator (INSTANCE is INTERFACE_TO_CHECK) or
- INSTANCE.GetType().GetInterfaces().Contains(typeof( INTERFACE_TO_CHECK ))
Tuesday, February 7, 2017
check for interfaces in c#
Wednesday, January 25, 2017
FakeItEasy essentials
FakeItEasy can be installed using nuget without any dependencies. Internally it uses the castle project (which makes me believe that FakeItEasy is more or less a super-powerfull dynamic proxy).
- A.Fake<class or interface>(); (also CollectionOfFake)
- tons of creation options can be added in overloaded Fake functions
- e.g: WithArgumentsForConstructor, Implements,...
- most interesting (for me) is .CallsBaseMethods so any object can be wrapped and be used with fakeiteasy magic
- A.CallTo(...); // Properties: A.CallToSet
- Arguments:
- exact: "1", "xyz",..
- by type: A<string>._
- Conditions: WithReturnType, Where, To
- ReturnValues: Throws, Returns, ReturnsNextFromSequence, ReturnsLayzily, ThrowsAsync, AssignOutAndRefParameters, AssignOutAndRefParametersLazily
- Behaviors: DoesNothing, CallsBaseMethod, Invoke
- Matchers: MustHaveHappened (Repeated), That.Matches(...)
- Raise.Wtih
Restrictions:
- can not be used with static or sealed classes
- methods that are not virtual or abstract can not be overriden
Saturday, January 21, 2017
Check for usb-sticks in windows
I wanted to check in my app whether usb sticks are connected or not (automatic recognition)...
Some research later I found the following article:
https://www.codeproject.com/Articles/63878/Enumerate-and-Auto-Detect-USB-Drives
works quite straight forward ...
things to mention:
- for different use-cases it might be enough to check Win32_LogicalDisk where drivetype=2
- in wpf you might use something like:
1 2 3 4 5 6 | protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); HwndSource source = PresentationSource.FromVisual(this) as HwndSource; source.AddHook(WndProc); } |
- when you disconnect a stick and call the wmi to show you data Win32_DiskDrive / Win32_LogicalDisk you get exception ... sleep and retry works after about 5 seconds.
- you can check the result in command line using "wmic logicaldisk get"
kr,
Daniel
Wednesday, January 18, 2017
C# code generation for databases
today I found SQLMetal.exe... https://msdn.microsoft.com/en-us/library/bb386987(v=vs.110).aspx
It is part of the visual studio installation and can create c# and vb code for different kind of db artefacts... I am curious how this works in comparison to Entity Framework (= T4).
kr,
Daniel
Friday, December 30, 2016
stateless - workflows in .NET
I found some frameworks for handling workflows:
- choose or build a class for State
- choose or build a class for Triggers
- create an object for a StateMachine<State,Trigger>
- initialization / get-set possibility to variables outside)
- configuring phase
- stateMachineObject.IsInState(stateItem)
- stateMachineObject.PermittedTriggers
- stateMachineObject.CanFire(triggerItem)
- stateMachineObject.Fire(triggerItem)
- stateMachineObject.FireAsync(triggerItem)
- stateMachineObject.Configure(stateItem)
- SubstateOf(stateItem) // Hierarchical State
- PermitReentry(Trigger)
- Permit(Trigger, State)
- PermitIf(Trigger, State, Guard)
- Ignore(Trigger)
- InternalTransition
- OnEntry(() => action());
- OnEntryAsync(async () => await action());
- OnEntryFrom(trigger, x => action()); // Parameterized Trigger
- OnExit(() => action());
Thursday, December 22, 2016
C# WCF WebOperationContext - best practice in error handling
WebOperationContext is typically used in a WCF REST method so that method can access the incoming request and outgoing response.(see: http://stackoverflow.com/questions/18747581/difference-between-weboperationcontext-current-and-httpcontext-current )
... in my projects I wrap OperationContract-ed methods with error handling. You can imagine that with a standard method like MessageWrapper which uses an Action or Function and implements the code in lambda-style in-line. The MessageWrapper handles the Exception handling and sets the Response ErrorCode (WebOperationContext.Current.OutgoingResponse.StatusCode) to 200 if everything is fine or to error if an exception occurred.
public T MessageWrapper(Func<T> action) where T : class{
try {
SetStatusOK();
return action();
} catch (Exception exc){
SetStatusError(exc);
return null;
}
public ReturnObject Operation() {
MessageWrapper(()=> return new ReturnObject("some", "parameters"));
}
... here I would love to mention, that with Castle you can create interceptors where you don't have to put the MessageWrapper inside the business logic code. You can keep this as an aspect (AOP) which can be configured at startup.
And here one more thing that helped a lot me during development time. You can set additionally to the StatusCode also a StatusDescription which e.g.: is displayed in your browser of choice as an explanation for an error. So StatusDescription = exc.Message is simply gold!
kr,
Daniel
Wednesday, December 14, 2016
monitor sql server table to track changes in .net c# projects
kr,
Daniel
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldependency.aspx
http://stackoverflow.com/questions/5288434/how-to-monitor-sql-server-table-changes-by-using-c
https://github.com/dyatchenko/ServiceBrokerListener
Thursday, December 8, 2016
WPF and Castle Windsor
Now after getting to know Castle Windsor and its ability to handle references it makes totally sense to solve that differently (or to be concrete: to solve that better). For development time we still need to hard code a design-time-view-model cause else we loose all the features of the IDE... Nevertheless Windsor should take over the control about the wiring of View and ViewModel. Main reason therefore is the power (features like Interceptors) and the flexibility (DynamicParameters, Load Config from XML, work with interfaces) coming up with.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class ActivatorWPFVM<T> : DefaultComponentActivator { public ActivatorWPFVM(ComponentModel model, IKernelInternal kernel, ComponentInstanceDelegate onCreation, ComponentInstanceDelegate onDestruction) : base(model, kernel, onCreation, onDestruction) { } protected override object CreateInstance(CreationContext context, ConstructorCandidate constructor, object[] arguments) { var component = base.CreateInstance(context, constructor, arguments); if(component is Window) { ((Window)component).DataContext = DIProvider.Container.Resolve<T>(); } return component; } } |
So by calling...
container.Register(
Component
.For<MainWindow>()
.Activator<ActivatorWPFVM<MainViewModel> >()
.LifestyleTransient());
Tuesday, November 29, 2016
Powershell-code inside of my application
I wanted to combine powershell and my .net application. In fact this works quite easily. The following link was quite helpful to make this work: https://blogs.msdn.microsoft.com/kebab/2014/04/28/executing-powershell-scripts-from-c/
We see here that an assembly has to be added (System.Management.Automation), but that's more or less it... I encapsulated the invocation of the powershell code into the following class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | using System.Management.Automation; using System.Collections.ObjectModel; class PSExecutor { protected Collection<PSObject> Execute(string command, params Tuple<string, object>[] parameters) { using (PowerShell PowerShellInstance = PowerShell.Create()) { // add a script that creates a new instance of an object from the caller's namespace PowerShellInstance.AddScript(command); parameters.ToList().ForEach(x => PowerShellInstance.AddParameter(x.Item1, x.Item2)); return PowerShellInstance.Invoke(); } } } |
... so we can use this class as a base class (if you want to call the execution of the code directly: change method Execute to be public). The following snippet is an example how to use the base class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // https://gallery.technet.microsoft.com/Get-WindowsUpdatesps1-7c82c1f4 class GetWindowsUpdatePSExecutor : PSExecutor { public Collection<PSObject> Execute() { return base.Execute( @" $UpdateSession = New-Object -ComObject 'Microsoft.Update.Session' $UpdateSearcher = $UpdateSession.CreateUpdateSearcher() $SearchResult = $UpdateSearcher.Search(""IsInstalled=0"") # ""IsInstalled=0 and Type='Software' and IsHidden=0"" $SearchResult.Updates |Select-Object -Property Title, Description, SupportUrl, UninstallationNotes, RebootRequired "); } } |
... with the snippet above you can check the OS for pending windows updates.
kr,
Daniel
Wednesday, August 3, 2016
Dates in WCF - JavaScript communication over JSON
today we had really big troubles with WCF and javascript communication. We wanted to send dates over the wire and use its value for additional libraries (which rely on type Date). After hours of playing around I finally solved it with JSON.parse.
Different approaches starting from overriding the WCF object serializer till writing a custom json parser libraries had been tried but finally all these are very unstable.
Resources I found to solve the problem
- Hanselman ... describing my problem
- Stackoverflow ... similar issue (solution mentioned)
- Documentation ... after knowing the solution a perfect page :-)
JavaScript/HTML testproject follows...
kind regards,
Daniel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | <html><head></head><body> <script> function test() { var objectString = '{"name" : "Daniel", "date" : "\/Date(1293034567877)\/"}'; //___________________________________________________________________________________ // var objectDataWithParse = JSON.parse(objectString); var objectDataWithDate = { "name": objectDataWithParse.name, "date": new Date(parseInt(objectDataWithParse.date.substr(6, objectDataWithParse.date.length-8))) }; function parseReviver(key, value) { var a; if (typeof value === 'string') { if(value.substr(0, 6) == '\/Date(') { alert(value.substr(6, value.length-8)); return new Date(parseInt(value.substr(6, value.length-8))) } } return value; }; var objectDataWithReviver = JSON.parse(objectString, parseReviver); //___________________________________________________________________________________ // var outObj = {}; outObj = objectDataWithDate; outObj = objectDataWithParse; outObj = objectDataWithReviver; //___________________________________________________________________________________ // document.getElementById('outputDIV_json').innerHTML = objectString; document.getElementById('outputDIV_name').innerHTML = outObj.name; document.getElementById('outputDIV_date').innerHTML = outObj.date; }; </script> <div> <button onclick="test()" >test</button> </div> <hr /> <div id="outputDIV_json" ></div> <div id="outputDIV_name" style="float:left;margin-right: 5px;margin-top: 5px; background: lightgreen"></div> <div id="outputDIV_date" style="float:left;margin-right: 0px;margin-top: 5px; background: orange"></div> </body></html> |
Sunday, June 26, 2016
Castle and WCF (3)
I went through hell to get this stuff work, but finally I got it. As partly mentioned in part 2 of this series I wanted to create an IIS hosted rest-service without the need of adding a svc-file. So I created an empty web-project, added a global.asax file and added the following code in the Application_Start method:
WindsorContainer container = new WindsorContainer();
There is no need to configure the service in the web.config-file except ASP.NET Compatibility which is needed by the Routes.Add code-line.
kind regards,
Daniel
Friday, June 17, 2016
Castle and WCF (2)
first of all I got the feedback that "Castle" is the wrong naming... so for clarification: with Castle the whole technology-stack of http://www.castleproject.org/ is meant including (especially) DynamicProxy and Windsor.
Further research brought me to the follow up question whether it is possible to implement a service with a non-empty (standard) constructor. Yes, this is also possible ( stackoverflow.com ). You simply need to:
- create a Custom-ServiceHostFactory (base class: ServiceHostFactory) and
- override CreateServiceHost which should create a Custom-ServiceHost.
- Each implemented service contract (loop over this.ImplementedContracts.Values) should get a Custom-Behavior (interfaces: IContractBehavior and IInstanceProvider) added.
- In the instance provider happens the magic of creating a service with new (override the two GetInstance-methods).
You can easily generalize this approach, and in fact some DI Containers have already done this for you (cue: Windsor's WCF Facility).A tutorial how to use the WCF facility can be found here and here. A walk-through "DI in WCF in 5min" can be found here (this article shows perfectly that DefaultServiceHostFactory enables you to create services with the full power of DI).
I am looking forward to test that approach with "RouteTable.Routes.Add(new ServiceRoute(...))".
kr, d
Thursday, June 16, 2016
Castle and WCF
it is a quite hard task to build a good and stable back-end. The request/response interfaces therefore are often full of boiler plate code. In my .NET applications I rely on WCF and REST services. First questions:
Can I create services on the fly or do I have to create a *.svc-file as described in 90% of the tutorials?
Answer: Yes... with ServiceHostFactory ( http://stevemichelotti.com/restful-wcf-services-with-no-svc-file-and-no-config/ )
Can I/Do I have to still use IIS?
Answer: Both is possible
Do I need to be a web.config expert?
Answer: You can config your stuff in code too.
So summarized: I can create ServiceHostFactories on the fly and can use Castle to inject the dependencies... great. Castle provides even more: WCF Integration Facilities... https://github.com/castleproject/Windsor/blob/master/docs/wcf-facility.md
There seemed to be an active community on writing facility based, config less, castle-driven backends like at https://github.com/vcaraulean/WcfWithoutConfigFile/blob/master/WcfWithoutConfigFile.WebHost.Castle/Global.asax.cs
... really cool... I am looking forward to use that stuff and post some first results...
kind regards,
Daniel
Friday, June 10, 2016
Dependency Injection with Windsor and WPF
this month I started reading about dependency injection and found out that castle.dynamicProxy (already mentioned in earlier posts) works great with castle.windsor. This might not be surprising but nevertheless after my first project using both nuget-packages I can definitely say that using these has changed my way of work. In this project my classes are shorter, better testable and my interfaces are more proper. (About a year ago I read the book about Clean Code Development by Robert C. Martin. The book is an advertisement for TDD with some pointers about coding style and development mind sets).
One thing to mention about my project using castle.windsor: it supports even more separation of Views and ViewModels of WPF. I used a custom Activator of generic type T (derived from DefaultComponentActivator) to activate my window and asked the windsor container to resolve a singleton viewModel of type T which can be set as the datacontext (override of CreateInstance). I stored the container as a static member of a centrally available class.
So:
- WPF-Activator<ViewModel>
- Still consider to set the DesignViewModel in the XAML code directly
- create a DIProvider
- use windsor - installers
- remove startup-uri in app.xaml and start mainwindow with showdialog
- prefer dependency injection over service locator pattern
- use interfaces instead of implementations
kr, D
Sunday, May 29, 2016
Book-Review: AOP in .NET (Matthew D. Groves)
Later it is shown which kind of aspects there are (those: for methods and those: for properties) and on which levels and ways these can be applied. The most important asset of the book is that it really makes it clear that there are different paradigms to make AOP. The first way described is "weaving" which actually changes the il-code in a post-compile step and "dynamic proxies" which create reflection-assemblies on the fly at runtime (the pros and cons are - in my opinion - the most important part of the book).
After reading the book i'm definitely able to write AOP code in .NET, but there are many references to IoC and DI so I would recommend to read a book about these first.
Kr, Daniel
Thursday, May 19, 2016
Castle DynamicProxy
I am currently reading a book about AOP in .NET (book review-post will follow soon). I really fell in love with Castle DynamicProxy and it probably works even better in combination with ninject (see: https://www.nuget.org/packages/Ninject.Extensions.Interception.DynamicProxy/ --> my next topic to dive into). The good thing here is that no weaving process is needed as post-build action. This means that if you debug, you debug the actual code and not manipulated code which might not match (or prevent debugging at all).
Crosscutting-concerns will be tackled by method-interception using a proxy:
var service = new ProxyGenerator().CreateClassProxy<Class1>(new Aspect());
- Aspect must implement IInterceptor.
- Class1 should have decorated its functions as virtual to create the appropriate proxy.
Often implemented aspects: logging, security, caching, threading (Invoke), lazy loading, INPC-implementation, exception handling, defensive programming and argument handling, validation, auditing, monitoring, fault tolerance.
kr, d
Wednesday, March 9, 2016
C# switch and double assigned enum values
Hi,
today I wanted to trick C#'s switch-case statement, but failed :-)
I tried to create an enum with 2 values pointing to the same value (yes this do is possible).
public enum TestEnum : uint
{
a = 1,
b = 1,
}
Main:
switch (variable)
{
case TestEnum.a:
Console.WriteLine("a");
break;
case TestEnum.b:
Console.WriteLine("b");
break;
default:
break;
}
... looking at the second part (only) this code makes perfect sense (as a test-case), but in combination it must be considered that the switch-case statement must find a unique case as a target and resolves the values behind the enumeration.
Compiler Error:
Error CS0152: The switch statement contains multiple cases with the label value '1'
... even if i failed to trick the compiler it is good news that c# is consistent here.
Kind regards,
Daniel
Tuesday, February 23, 2016
Filter DataGrid in C#/WPF using ICollectionView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <Window x:Class="FilteringGrids.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:FilteringGrids" mc:Ignorable="d" Title="Filter-Test" Height="350" Width="525" DataContext="{Binding Main, Source={StaticResource Locator}}"> <Grid Margin="10"> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="1*" /> </Grid.RowDefinitions> <TextBox Grid.Row="0" Text="{Binding FilterText}" Margin="0,0,10,10"></TextBox> <Button Grid.Row="0" Grid.Column="1" Margin="0,0,10,10" Height="25" Width="50" Command="{Binding RefreshCommand}">Refresh</Button> <Button Grid.Row="0" Grid.Column="2" Margin="0,0,0,10" Height="25" Width="50" Command="{Binding FilterCommand}">Filter</Button> <DataGrid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" ItemsSource="{Binding Data}" /> </Grid> </Window> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.CommandWpf; using System; using System.Collections.Generic; using System.ComponentModel; using System.Windows.Data; using System.Windows.Input; namespace FilteringGrids.ViewModel { /// <summary> /// This class contains properties that the main View can data bind to. /// <para> /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel. /// </para> /// <para> /// You can also use Blend to data bind with the tool's support. /// </para> /// <para> /// See http://www.galasoft.ch/mvvm /// </para> /// </summary> public class MainViewModel : ViewModelBase { public class Model { public string Name { get; set; } public string Value1 { get; set; } public string Value2 { get; set; } public string Value3 { get; set; } public string Value4 { get; set; } } /// <summary> /// Initializes a new instance of the MainViewModel class. /// </summary> public MainViewModel() { #region Filter FilterText = ""; Predicate<object> filterFunction = (object raw) => { Model dataToFilter = raw as Model; return dataToFilter.Name.Contains(FilterText) || dataToFilter.Value1.Contains(FilterText) || dataToFilter.Value2.Contains(FilterText) || dataToFilter.Value3.Contains(FilterText) || dataToFilter.Value4.Contains(FilterText); }; FilterCommand = new RelayCommand(() => DataCollectionView.Refresh(), () => true); #endregion #region Init / Refresh RefreshCommand = new RelayCommand(() => { Data = new List<Model> { new Model() { Name="one", Value1="1", Value2="1.0", Value3="1.00", Value4="1.000" }, new Model() { Name="two", Value1="2", Value2="2.0", Value3="2.00", Value4="2.000" }, new Model() { Name="three", Value1="3", Value2="3.0", Value3="3.00", Value4="3.000" }, new Model() { Name="four", Value1="4", Value2="4.0", Value3="4.00", Value4="4.000" }, }; DataCollectionView = CollectionViewSource.GetDefaultView(Data); DataCollectionView.Filter = filterFunction; this.RaisePropertyChanged("Data"); }, () => true); // init data RefreshCommand.Execute(null); #endregion } public string FilterText { get; set; } public List<Model> Data { get; set; } private ICollectionView DataCollectionView { get; set; } public ICommand RefreshCommand { get; set; } public ICommand FilterCommand { get; set; } } } |
What we see here is that 99% of the magic happens in the constructor of the viewmodel. This is bad style, but keeps the things easy for the example, so please forgive me here. We see here that all members (defined at the end of the class) are bound by the xaml-code except the CollectionView which is used for the actual filtering.
- if you change the reference of your data source then populate that to the UI (INPC -> RaisePropertyChanged)
- Filtering over ICollectionView is easily achievable over a Predicate-function
- recreate the ICollectionView if the original instance of the data changes (you probably don't need a reference to this)
- if the filter-result might change call CollectionViewInstance.
Refresh()
Tuesday, February 16, 2016
Closures in JavaScript and C#
today I dug deeper into the world of javascript closures and found an interesting mozilla.org -page explaining the topic of closures perfectly. I started getting curious about how implementations like in https://jsfiddle.net/v7gjv/ as described in https://developer.mozilla.org/en/docs/Web/JavaScript/Closures#Creating_closures_in_loops_A_common_mistake could look like in C# and whether the same solutions lead to same success.
The problem depicted in the article referenced above is that a closure was used wrongly inside the method "setupHelp".
1 2 3 4 5 6 | for (var i = 0; i < helpText.length; i++) { var item = helpText[i]; document.getElementById(item.id).onfocus = function() { showHelp(item.help); } } |
The problem (quote taken over from the article):
The reason for this is that the functions assigned toIn the article a solution was provided. They used a function factory method, but I think the following solution is a bit better (even if it is possibly the same thing, but with less code and without the need of jumping around on the screen; the cleanliness of this solution might be doubted, but I do like this version the most):onfocusare closures; they consist of the function definition and the captured environment from thesetupHelpfunction's scope. Three closures have been created, but each one shares the same single environment. By the time theonfocuscallbacks are executed, the loop has run its course and the item variable (shared by all three closures) has been left pointing to the last entry in thehelpTextlist.
1 2 3 4 5 6 7 8 9 | for (var i = 0; i < helpText.length; i++) { var item = helpText[i]; document.getElementById(item.id).onfocus = function() { var myItem = item; return function() { showHelp(myItem.help); } }(); } |
... here we create an anonymous function on line 3 and call it instantly on line 8 to return an actual event handler (line 5). This function call brings us in a new scope in which we can access the variable from line 2 on line 4 and store it inside of our new scope to use it in line 6 from the event handler.
So... can we have such problems in C#?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | class Program { class MenuItem { public event EventHandler<EventArgs> onfocus; public void Call_onfocus() { onfocus(this, EventArgs.Empty); } } static void showHelp(string name, string help) { Console.WriteLine("{0,7}: {1}", name, help); } static void Main(string[] args) { var helpText = new List<Tuple<string, string>>{ new Tuple<string, string>("email", "Your e-mail address"), new Tuple<string, string>("name", "Your full name"), new Tuple<string, string>("age", "Your age (you must be over 16)"), }; var document = new Dictionary<string, MenuItem>(); helpText.ForEach(x => document.Add(x.Item1, new MenuItem())); for (var i = 0; i < helpText.Count; i++) { var item = helpText[i]; document[item.Item1].onfocus += (sender, e) => { showHelp(item.Item1, item.Item2); }; } document.ToList().ForEach(x => x.Value.Call_onfocus()); } } |
Unfortunately the version that breaks in javascript works just fine in C#. So I needed to change a bit in the for-loop to demonstrate the problem...
1 2 3 4 5 6 7 | for (var i = 0; i < helpText.Count; i++) { document[helpText[i].Item1].onfocus += (sender, e) => { showHelp(helpText[i].Item1, helpText[i].Item2); }; } |
The for-loop now accesses the array directly and here we are... out-of-range-exception,.. boom... because i is 3 when the Call_onfocus (line 36 in the listing above) calls the event calling showHelp (line 5).
Now we know, that the problem is also a real-world problem in .NET environments. Can we now take over the way to fix the issue in javascript to the C# world? It would be helpful to know one working solution for two (or all kind of) different worlds.
I was able to do so, but I admit the solution is a bit ... let's say: different.
1 2 3 4 5 6 7 8 9 10 11 12 13 | for (var i = 0; i < helpText.Count; i++) { document[helpText[i].Item1].onfocus += ( new Func<EventHandler<EventArgs>>( () => { var myItem = i; return (sender, e) => { showHelp(helpText[myItem].Item1, helpText[myItem].Item2); }; })()); } |
... as we can see here: I reused the solution of listing #2 and stored the changing value into a newly created scope I created by writing an ad-hoc function I instantly call.
The good things here are that we are not limited to pass in data through event args and minimize the lines of code/number of declared functions, but to be honest I would not recommend to use this kind of hoax too much...
kind regards,
Daniel
Friday, December 4, 2015
Debugging return values in C#
1 2 3 4 | public bool CheckExists(string itemId) { return ItemList.Exists(item => item.ItemId == itemId); } // <- breakpoint |