In Which @Captain asks C# Beginner Questions


  • Winner of the 2016 Presidential Election

    @Captain If you're interested in languages with very powerful type systems, Ceylon might also be interesting to you.



  • I hope we don't mind if I steer the conversation back towards the Microsoft ecosystem.

    Does Powershell allow writing functions that take functions as arguments? I want something like:

    function InExchange365Context ($run)
    {
    
    # Connect to Exchange, make a Powershell Session for it.
      $UserCredential = Get-Gredential;
      $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection;
      Import-PSSession $Session;
    
      $run;
    
    # Close the Powershell Exchange Connection:
      Remove-PSSession $Session;
    } 
    

    so that I can do stuff like pass in a block to run.

    I suspect this will be a bit of a pain in the ass using Powershell (or even C#). Haskell is pretty different in how it treats "statements" versus "expressions." Both are just values (statements are monadic values), and the mechanics of passing values around isn't any different between them. I can easily write a type for a function that accepts a "statement" (i.e., a monadic value) and function application works just the same. Something like:

    inFooContext :: IO () -> IO () 
    inFooContext run = do
      connectToFoo
      run
      disconnectFromFoo
    

    We see that run is an IO action that returns (), and inFooContexts accepts an IO () and is an IO (), so the function call would look like:

     inFooContext  (putStrLn "I'm printing a line in Foo!")
    

    or

    inFooContext do
      putStrLn "I'm launching the missiles!"
      launchTheMissiles

  • Winner of the 2016 Presidential Election

    @Captain said in In Which @Captain asks C# Beginner Questions:

    I hope we don't mind if I steer the conversation back towards the Microsoft ecosystem.

    Does Powershell allow writing functions that take functions as arguments? I want something like:

    function InExchange365Context ($run)
    {
    
    # Connect to Exchange, make a Powershell Session for it.
      $UserCredential = Get-Gredential;
      $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection;
      Import-PSSession $Session;
    
      $run;
    
    # Close the Powershell Exchange Connection:
      Remove-PSSession $Session;
    } 
    

    so that I can do stuff like pass in a block to run.

    I suspect this will be a bit of a pain in the ass using Powershell (or even C#). Haskell is pretty different in how it treats "statements" versus "expressions." Both are just values (statements are monadic values), and the mechanics of passing values around isn't any different between them. I can easily write a type for a function that accepts a "statement" (i.e., a monadic value) and function application works just the same. Something like:

    inFooContext :: IO () -> IO () 
    inFooContext run = do
      connectToFoo
      run
      disconnectFromFoo
    

    We see that run is an IO action that returns (), and inFooContexts accepts an IO () and is an IO ().

    I think you should be able to - this might lead you to more specific information.

    In C#, it's not hard. One way would be to pass an Action<> or Func<> delegate and Invoke() it:

    void someFunction(Action a) { a.Invoke(); }
    
    //...
    
    someFunc(() => Console.WriteLine("Aye Aye, Captain!"));
    


  • @Dreikin there's also the () syntactic sugar for .Invoke() if anyone cares. You just can't ?. it that way. @Captain if you need a different delegate somehow, just look up delegates in c#. You probably won't.



  • @Captain said in In Which @Captain asks C# Beginner Questions:

    That is a "multi-param type class", and it lets method resolution depend on more than one type. You can use multi-param type classes to implement things like relations and functions at the type level.

    Something like this:

    class Store<T, U>
      where T : IEnumerable<U>
    {
    }
    

    I mean, it's goofy but I think that matches your example.

    (To instantiate the class, we have to do it like: var blah = new Store<List<Foo>, Foo>(). But you get the probably-useless "advantage" that you can swap-out the List for any other class that implements IEnumerable.)



  • @Captain Are you learning C# purely so you can lecture everybody on how great Haskell is?

    Because that's how it's coming across.



  • @blakeyrat it would still be better than he lecturing us without knowing C#, so go on



  • @fbmac I think he asked that about PowerShell because he wanted to show-off that Haskell could do it easily, but he also deep in his heart knew that C# could also do it easily.

    But if you switch the .net language to PowerShell, suddenly nobody knows if it can be done easily (because PowerShell is not typically used that way) and then he has a chance to tell us how great Haskell is once again.

    I got your number. I got all your numbers!



  • @blakeyrat we wouldn't be able to learn haskell without remembering how cool C# is in every detail that haskell happens to be annoying or just different too, would we?

    damn, I'm not using C# for some 2 years, and I keep missing features from it, like having a "string" type



  • @blakeyrat

    I'm using PowerShell now because that's the language Microsoft uses to administer Exchange and I have to set up permissions on like 100 calendars.

    So yeah, since I'll have to administer the company's Exchange configuration, it only makes sense to wrap the context up into a function and pass it commands to run "remotely" instead of copy-pastaing that context into every administration script I write.



  • Now I'm shopping for a cheap Android phone to use as an MP3 player for our PBX system's hold music. Operations management is varied.


  • I survived the hour long Uno hand

    @Captain said in In Which @Captain asks C# Beginner Questions:

    Does Powershell allow writing functions that take functions as arguments?

    This is more powershell-y:

    $Session = New-PSSession -ComputerName "${computerName} -UseSSL -credential $cred
    
    $Result = Invoke-Command -Session $Session -FilePath './script2.ps1' -ArgumentList $foo,$bar,$bat
    
    Remove-PSSession $Session;
    
    exit $Result
    

    You could easily pass in the filename, then make short script files to do common tasks. Voila.



  • @Yamikuronue so if I get what you're saying, I'd have my "context" script (the one that manages the connection to exchange) run Invoke-Command and pass in a filename to the context script so it knows what to invoke.


  • I survived the hour long Uno hand

    @Captain Yeah. That downloads the script to the remote machine and runs it there, so everything local becomes "local to that machine".


  • Considered Harmful

    @Captain said in In Which @Captain asks C# Beginner Questions:

    PBX system's hold music

    So you're to blame!



  • @error I'm going to play some Paganini. And maybe sneak a Can track in there.


  • ♿ (Parody)

    @Captain said in In Which @Captain asks C# Beginner Questions:

    That is a "multi-param type class", and it lets method resolution depend on more than one type. You can use multi-param type classes to implement things like relations and functions at the type level.

    Sorry, I followed your explanation of the monomorphic type class. These words are interesting but I don't understand how they apply to the code Store code.



  • @boomzilla It's a bit hard to show without having a problem to solve. One application is what's called "Data Types a la Carte" style, where we define a :<: relation to mean that there is an embedding of one type into another.

    class (:<:) a b where
       inject :: a -> b
       project :: b -> Maybe a
    

    So this is very much like the IsString class, except you're really saying that an a is a b. The data types a la carte style defines a sum operator :+: by

     data (:+:) a b = InLeft a | InRight b
    
     -- set fixity so that (:+:) is right associative and does what I want.  I agree this bit is ugly and magical but it is what it is:
     infixr 6 (:+:)
    

    and then we make instances for :<: with it, like

    instance a :<: a where
      inject = id
      project = Just
    

    which tells us we can cast from a to a with the identity function, and down-cast by just assuming it works. Similarly,

    instance a :<: (a :+: b) where
       inject a = InLeft a
       project (a :+: _) = Just a
       project _ = Nothing
    

    This code tells us that we can turn an a into an a :+: b with inject, and maybe cast back down with project. The last instance we need to make data types a la carte work, if I remember correctly, is:

    instance (b :<: c) => (b :<: a :+: c) where
      inject b = InRight $ inject b
      project (a :+: bOrC) = project bOrC
    

    There's a point to all this, but I don't have time to motivate much more. The upshot is that with this machinery, if you can write "generic" functions that work for any type "bigger" than what the function "needs"

    mixTheCake :: ( CheckSafety :+: CheckPower :<: checkWorld ) => checkWorld -> IO ()

  • ♿ (Parody)

    @Captain said in In Which @Captain asks C# Beginner Questions:

    The upshot is that with this machinery, if you can write "generic" functions that work for any type "bigger" than what the function "needs"

    At this point, being no more enlightened, I'm going to take your word for it and be happy with my blubish ignorance. Thanks for the attempt, though.



  • @boomzilla the aspect most germane to your question is how :<: defines a partial order on an algebra of types. We can't "query" that data structure directly, really. (At least not without more advanced techniques) But the compiler knows about it and uses it to reject bad programs.



  • @blakeyrat said in In Which @Captain asks C# Beginner Questions:

    But if you switch the .net language to PowerShell, suddenly nobody knows if it can be done easily (because PowerShell is not typically used that way)

    Pretty sure passing code blocks around is a fairly ubiquitous concept in PS. Invoke-Command certainly does that, though I've never bothered to read up how.

    Invoke-Command -Computername $RemoteComputer -ScriptBlock { Get-ChildItem "C:\Program Files" }
    


  • @boomzilla All you have to do is Frob the &^(**& xwelxteen times with a cragstop.


  • Winner of the 2016 Presidential Election

    @Captain said in In Which @Captain asks C# Beginner Questions:

    The upshot is that with this machinery, if you can write "generic" functions that work for any type "bigger" than what the function "needs"
    mixTheCake :: ( MixerSafety :+: CheckPower :<: stateOfWorld ) => stateOfWorld -> IO ()

    Side note: You just implemented a part of Ceylon's type system in Haskell. ;)



  • @asdf Ceylon does look pretty cool. I'm so far behind the state of the art in Haskell I might try something new.

    Plus runtimes in Java and JavaScript sound pretty excellent. Full stack development in a type safe language is very appealing.



  • @Captain said in In Which @Captain asks C# Beginner Questions:

    I guess I want to be able to write PowerShell scripts, and have the IDE do all the scaffolding, and have Intellisense for PowerShell functions. Ideally within VS so I don't have to learn yet another shitty Windows text editor. VisualStudio is fairly nice anyway.

    Why not just use Powershell ISE?



  • @rad131304 Because it' forces another shitty text editor on me.


  • Considered Harmful

    @Captain said in In Which @Captain asks C# Beginner Questions:

    @rad131304 Because it' forces another shitty text editor on me.

    I'm pretty sold on Atom as a code editor. My only real frustration is that it locks files and directories that are open, which makes my gulp and grunt clean tasks fail with EPERM. (No editor is frustration free, in my experience.)


    Filed under: Now we can 🔥 about text editors for a few hundred posts or so.





  • @blakeyrat said in In Which @Captain asks C# Beginner Questions:

    @Captain It also doesn't care if you add a trailing comma:

    list = [
      theFirst,
      theSecond,
      theThird,
    ];
    

    Which is brilliant and every programming language should support it dammit.

    Go requires it.


  • Considered Harmful



  • @ben_lubar d-lang looked so promising, why did it fail?



  • @fbmac

    I'd like to know that too. What I "heard" is that there was a split in the community about the standard library and the solution didn't please anybody.



  • @Captain from what I read, I was liking it more than go or rust.

    but I didn't try it because the htod program, used for converting C headers to D consumption, was Windows only



  • @fbmac :wtf:

    I was too young to appreciate what it brought to the table when it was gaining popularity. I was still in my weak typing phase. And I never liked C, so D's marketing didn't appeal to me. It did sound like a good idea, but I never cared.



  • @Captain looking again, still windows only htod. fuck those guys, next language I'll learn is probably go



  • I'm making my first WPF application, and I'm stuck on defining a user control.

    I want to be able to call my usercontrol like:

    <MainPanel Title="The Title that gets mapped to a Tab header and a few other places" />
    

    My user control XAML file looks like:

    <UserControl x:Class="Local.MainPanel"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Local"
             mc:Ignorable="d" 
             d:DesignHeight="331" d:DesignWidth="400">
    
      <TabItem Header="{Binding local:Title}" Style="{StaticResource SideTab}" />
    
    </UserControl>

    The user control class looks like:

    public partial class MainPanel : UserControl
    {
        public MainPanel()
        {
            InitializeComponent();
        }
    
        public string Title { get;  set; }
    }
    

    This all compiles. The problem: the binding isn't working. I expect my call like

    <TabControl TabStripPlacement="Left">
      <local:MainPanel local:Title="Panel Title">
        <contents go here>
      </local:MainPanel>
    </TabControl>
    

    to add a "panel" named "Panel Title" to my main window. The call adds the panel, but as far as I can tell, the TabItem heading is empty or null. It definitely doesn't show "Panel Title" on the screen.

    Secondary questions:

    1. Is there any easier way to include XAML snippets than a usercontrol? I guess my instict is to want to use user controls as a way to name specific controls, while keeping the layout and styling stuff as generic as possible. So I'll want to pass the "business logic" xaml in to the generic styling xaml.

    2. Can I use more fine-grained names for my XAML namespaces? I'm thinking I'd like to use a namespace for each of my major layouts, so I could have stuff like <main:Panel>, <product:Panel>, etc. What would it take to make that happen?



  • @Captain You'll need to implement INotifyPropertyChanged or change the Title property to be a dependency property.



  • @Captain Styles can be included separately as a resource dictionary. Typically, this is how you'd style a customcontrol. User controls are typically detailed content sections. Your main binding problem is that wpf doesn't know what object to look in for your binding: It knows the type, but you haven't assigned a datacontext. That should be enough. Also, if you look in my mvvm thread, there should be a sample wpf project that might be a useful reference for some of the basics.



  • I'm still trying to figure out the binding stuff. Maybe.

    My MainWindow has

    <TabControl TabStripPlacement="Left" Grid.RowSpan="2">
      <TabItem Header="Left" Style="{StaticResource SideTab}" />
      <local:MainPanel PanelTitle="Right" />
    </TabControl>
    

    The MainPanel is basically just a wrapper widget around a TabItem. For now, all the wrapper does is add style, but it will deal with layouts later. It is literally just

    <UserControl x:Class="PsychOps.MainPanel"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:PsychOps"
             mc:Ignorable="d" 
             >
    
      <TabItem Header="{Binding Path=PanelTitle}" Style="{StaticResource SideTab}" Name="PanelRoot"/>
    </UserControl>
    

    It's acting funny:
    0_1467415222524_right-wrong.PNG

    What's going on here? It looksl ike the "Header" is getting attached to the wrong thing (the TabItems contents). Is that what's going on? How do I fix it?



  • @Captain did you set the data context? I'm not sure how you expect your panel to know what It's trying to bind to, and you aren't giving it content anywhere. Seriously, check out my mvvm topic, the example there has all you need to know about bindings.



  • @Magus said in In Which @Captain asks C# Beginner Questions:

    @Captain did you set the data context? I'm not sure how you expect your panel to know what It's trying to bind to, and you aren't giving it content anywhere. Seriously, check out my mvvm topic, the example there has all you need to know about bindings.

    I don't get what you're asking. The way I see it (and maybe I don't understand), my call

    <local:MainPanel PanelTitle="Foo">
    

    to my user control

    <UserControl x:Class="PsychOps.MainPanel"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:PsychOps"
             mc:Ignorable="d" 
             >
    
      <TabItem Header="{Binding Path=PanelTitle}" Style="{StaticResource SideTab}" Name="PanelRoot" />
    </UserControl>
    

    should set the TabItem's Header to be "Foo", given then I have set up

    public partial class MainPanel : UserControl
    {
        public MainPanel()
        {
            InitializeComponent();
            PanelRoot.DataContext = this;
        }
    
        public static readonly DependencyProperty PanelTitleProperty = DependencyProperty.Register("PanelTitle", typeof(String), typeof(MainPanel));
    
        public string PanelTitle
        {
            get { return (string)GetValue(PanelTitleProperty); }
            set { SetValue(PanelTitleProperty, value); }
        }
    }
    

    So I look at my code and I look at your code and I don't see very many relevant differences. It almost looks like the PanelTitle is getting bound to the wrong tag.

    I sort of followed this tutorial. http://blog.scottlogic.com/2012/02/06/a-simple-pattern-for-creating-re-useable-usercontrols-in-wpf-silverlight.html



  • @Captain That does seem like it should work, though I think in your case I would have set the binding to be {Binding PanelTitle, Element=PanelControl}, set x:Name="PanelControl" on your usercontrol, and not messed with the datacontext.

    Or else go with a viewmodel and INotifyPropertyChanged. Even here, INotifyPropertyChanged would be enough apart from some really weird cases you probably won't be dealing with... Basically, apart from customcontrols, which maybe this should actually be, (subclass TabItem, there are tutorials online), it's very rare to see a dependency property.



  • @Captain
    Following works for me. Only caveat is the XAML Designer won't show the default binding correctly on the CustomPanel but if you throw the custom panel in another control it binds correctly.

    <UserControl x:Class="WpfFunTimes.CustomPanel"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:local="clr-namespace:WpfFunTimes"
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300" x:Name="ControlRoot">
    
        <TabItem Header="{Binding Path=Title, ElementName=ControlRoot}"  Name="TabItemRoot"/>
        
    </UserControl>
    
        /// <summary>
        /// Interaction logic for CustomPanel.xaml
        /// </summary>
        public partial class CustomPanel : UserControl
        {
            public CustomPanel()
            {
                InitializeComponent();
            }
    
            public static readonly DependencyProperty TitleProperty =
                 DependencyProperty.Register("Title", typeof(String),
                 typeof(CustomPanel), new FrameworkPropertyMetadata("Default Title"));
    
            public string Title
            {
                get { return (string)GetValue(TitleProperty); }
                set { SetValue(TitleProperty, value); }
            }
        }
    


  • Here's what I get

    0_1467468621807_right-wrong.PNG

    Notice that the "Correct" tab has the tab heading thingie on the left, in the tab bar. On the other hand, the custom control has an empty tab heading thingie in the tab bar, and it looks like it has a tab heading.

    <TabControl TabStripPlacement="Left"
                Grid.RowSpan="2"
                >
      <TabItem Header="Correct" />
      <local:MainPanel Title="Wrong" />
    </TabControl>
    

    So it looks like the custom control is making a tab item , and then binding to the wrong one, kind of like

    <TabControl TabStripPlacement="Left"
                Grid.RowSpan="2"
                >
      <TabItem Header="Correct" />
      <TabItem>
        <TabItem Header="Wrong" />
      </TabItem>
    </TabControl>
    

    So I don't get it. How can I include arbitrary XAML in a XAML file? I thought that's what UserControls were for.



  • @Captain Okay the problem you are facing is UserControl is only a ContentControl where a TabItem is a HeaderedContentControl. UserControl doesn't "know" how to render "correctly" in a TabControl.

    Is MainPanel only meant to be used in a TabControl or could it be used in other ContentControls?



  • @MathNerdCNU It would be (potentially) useful, but not necessary, for the MainPanel to work elsewhere.

    Uncaught type errors piss me off!

    I'm working on an exporter project now (the same one I talked about like 200 posts ago), and it totally type checks and doesn't throw any errors and it refuses to write to a file for no fucking reason I can tell.



  • @Captain said in In Which @Captain asks C# Beginner Questions:

    I'm working on an exporter project now (the same one I talked about like 200 posts ago), and it totally type checks and doesn't throw any errors and it refuses to write to a file for no fucking reason I can tell.

    We can probably help with that too.

    Still, did you play around with my MEF-based project? I keep bringing it up because people have issues with certain things like bindings and data contexts and DI, and I've got them all implemented simply there.



  • @Magus said in In Which @Captain asks C# Beginner Questions:

    Still, did you play around with my MEF-based project? I keep bringing it up because people have issues with certain things like bindings and data contexts and DI, and I've got them all implemented simply there.

    Yeah, I took a look at it, but I haven't touched that project since Friday. No time for big changes there.

    We can probably help with that too.

    Thanks! So the basic flow is:

    1. run a database query
    2. for each row, format the row and append the formatted text to result
    3. convert result to a memory stream
    4. write result to an Sftp consumer, which takes a stream.

    but since I'm "testing", I'm actually doing (for now):

            using (var resultStream = new MemoryStream(Encoding.UTF8.GetBytes(result)))
            using (var fileStream = new FileStream(Path.Combine(Application.StartupPath, filename), FileMode.Create, FileAccess.Write) )
            {
                // write the file
                resultStream.WriteTo(fileStream);
    
                // upload the file
                //Console.WriteLine("Creating sftp client and connecting.");
                //sftp.Connect();
                //Console.WriteLine("Connected to {0}", host);
                //sftp.ChangeDirectory(workingdirectory);
                //Console.WriteLine("Changed directory to {0}", workingdirectory);
    
                //Console.WriteLine("Uploading MOTS results ({0:N0} bytes)", resultStream.Length);
                //sftp.BufferSize = 4 * 1024; // bypass Payload error large files
    
                //sftp.UploadFile(resultStream, workingdirectory + "/" + filename);
            }
    

    The program is opening my file, and writing 0 bytes to it.



  • @Captain Is result a string?

    You could try File.Write() perhaps.



  • @Magus It was a dumb bug with one variable shadowing another one. I had result defined as a static string and then I defined result in Main and the wrong one was getting printed.

    No warnings for shadowed variables, apparently...


Log in to reply