Avatar billede Slettet bruger
05. august 2009 - 19:37 Der er 38 kommentarer og
1 løsning

Finde referencer i kildekoden

Hej eksperter,

Som et eksperiment er jeg ved at udvikle et lille program, der kan analysere forbindelser mellem hjemmesiders undersider og eksterne elementer. Jeg henter kildekoden med et HTTP request og arbejdet så ved at finde samtlige filer og direktorier (da /test/ => /test/index.*) nævnt i koden. Hvordan kan jeg mest effektivt lave et REGEX, der finder alle disse referencer? Hvad skal jeg kigge efter?
Avatar billede aaberg Nybegynder
05. august 2009 - 20:50 #1
overvej at bruge HTML Agility Pack. Den giver mulighed for at søge i html dokumenter med xpath.
http://www.codeplex.com/htmlagilitypack
Avatar billede Slettet bruger
05. august 2009 - 23:22 #2
Tak. Jeg prøvede lige at rode med syntaksen for en vilkårlig reference...
["|']{[http://([sub.]domain.super|ip)[:port]}|/|{path}|/|{file.ext}[?a=b&c=d][#e]["|']
Hvor første og sidste [] danner par, mindst én {} skal forekomme, og || skal indgå, hvis begge omkringliggende {} eksisterer. Ovenstående kan givetvis ikke alene anvendes, da den grundet hensyn til relative referencer til direktorier godtager enhver streng. Derfor vil jeg starte med at anvende Agility Pack og se på de mere komplekse referencer senere :)
Avatar billede Syska Mester
06. august 2009 - 00:45 #3
Det er et godt sted at starte ...

Så skal du bare lede med alle links på siden ... hente dens href ud ...

Derefter kan du jo teste om den er relativ eller ej, da du jo kender siden du er på om se om den er prefixed dine urls/links

// ouT
Avatar billede Slettet bruger
06. august 2009 - 16:54 #4
Jeg har forresten lige oplevet den underligste fejl... Hvis en TextBox er sat til ReadOnly=true i VS2010 beta 1, får man kritiske fejl, når man via kode ændrer Text :)
Avatar billede Slettet bruger
06. august 2009 - 16:59 #5
Der var jeg vist lidt for hurtig; det var bare mig, der havde lavet en grum fejl :)
Avatar billede Slettet bruger
06. august 2009 - 22:33 #6
Godt, jeg tror, jeg har styr på det nu så smid bare et svar (eller to, hvis I er lidt socialistiske).

Et lille ekstra spørgsmål: Enhver metode kaldt fra en tråd vil eksekveres i tråden selv og ikke den tråd hvor metoden er oprettet, korrekt? Eksempel: Jeg har en klasse med en række metoder. En af metoderne opretter en tråd ud fra en anden metode. Den anden metode skal så til sidst starte den første, så en ny tråd med den anden funktion afløser den nuværende osv. Hvis jeg kalder den første funktion i den anden, vil den første imidlertid eksekveres i den nye tråd og ikke den oprindelige, korrekt?
Avatar billede Syska Mester
06. august 2009 - 22:54 #7
say what ... udover jeg ikke lige er med så . ..


Tråd 1 ( main tråden ) starter 10 tråde ... de er nu alle selvstændige(på sin vis, kan dog stadig godt snakke med hianden) og alle de klasser/metoder de måtte tråde opretter bliver eksekveret i selve tråden.

mvh
Avatar billede Syska Mester
06. august 2009 - 22:54 #8
svar
Avatar billede Slettet bruger
07. august 2009 - 00:01 #9
Jeps, men hvis en af de 10 tråde kalder en metode fra det objekt, der oprettede dem i den første tråd, i hvilken tråd eksekveres metoden så?
Avatar billede Syska Mester
07. august 2009 - 00:47 #10
Samme som kaldte den metoder på det object du kalder metoder på.

Du skal bare være klar over at der kan opstå problemer ved det ...

En tråd Disposer et object ... det kender den anden tråd jo ikek noget til og tror det stadig findes ... og så har du lige pludselig en Null reference Exception.

Så dus kal have tunget lige i munden.

Men det er der skrevet _MEGET_ om på nettet.
Avatar billede Slettet bruger
07. august 2009 - 01:57 #11
Jeps. Jeg tænker mig lige godt om :)

aaberg, point?
Avatar billede Slettet bruger
07. august 2009 - 03:36 #12
Threads are blowing my mind, man...

Nu står jeg med et problem, jeg ikke helt kan hitte rede i; jeg har følgende tråde:
- Hovedtråden til mine forms
- Kontroltråden til styring af arbejdstråde
- Arbejdetråde til download og analyse af kildekoder
- Arbejdstråde til download og smmenligning af filer

Jeg har en metode under hovedtråden, der skriver til et tekstfelt (til generelt output). Jeg kan selvfølgelig godt få lov til at kalde metoden fra de øvrige tråde, men .NET bliver ked af det, når metoden så skal skrive til tekstfeltet og siger med gråd i stemmen:
"Cross-thread operation not valid: Control 'TextBox_Output' accessed from a thread other than the thread it was created on."
Now what can I do? :(
Avatar billede Slettet bruger
07. august 2009 - 03:40 #13
Det kan godt ske, man bliver nødt til at være kreativ her, så jeg kan vist lige så godt uddybe sagen:

Hovedtråden står sådan set og laver ingenting; den viser bare vinduet. Når så jeg har behov for at outputte noget (sker altid gennem kontroltråden), skal der pilles ved tekstfeltet, og hvis dette SKAL gøres fra hovedtråden, skal jeg sådan set bare bruge en måde at sende et røgsignal fra kontroltråden til hovedtråden om, at den skal lette røven og kalde metoden. How, oh, how?
Avatar billede aaberg Nybegynder
07. august 2009 - 08:33 #14
Hvis du skal ændre på brugergrænsesnittet fra en anden tråd end hovedtråden, bliver du nød til at kalde Invoke(). Ellers får du en "Cross-thread operation not valid" fejl.
http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx

Men, når det er sagt, pas på når du bruger tråde. Keep it simple! Og det er meget vigtigt! Hvis du laver noget meget kompliceret kommunikation imellem tråde, som jeg synes det lyder som om du har gang i, så ender programmet med at blive skyldet ud i lokummet. Multithreading er kompliceret, og kan potentielt skabe deadlocks og exceptions som er næsten umulige at finde.

Hvis jeg var dig ville jeg se på BackgroundWorker klassen. Dette er et komponent som kan køre en baggrundstråd, og som sørger for at du ikke falder i mange af de faldgruber som multithreading har.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
Avatar billede aaberg Nybegynder
07. august 2009 - 08:39 #15
Hvis du ikke kan bruge en BackgroundWorker, da kan du selvfølgelig godt bruge Thread klassen eller ThreadPool klassen. Bare sørg for at holde det så simpelt som muligt :-)

Du har tidligere skrevet at programmet du skriver er et eksperiment, og da kan det være en god ide og få rodet lidt med tråde. Det er jo eksperimenter man lærer af :-)
Avatar billede Syska Mester
07. august 2009 - 12:29 #16
ja ... jeg plejer så at sige det på en anden måde.

Det er ens fejl man lærer af *heheh*
Avatar billede Slettet bruger
07. august 2009 - 12:45 #17
#15+16
Præcis, jeg skulle også til at skrive, at når nu jeg alligevel eksperimenterer, kan jeg da lige så godt lære lidt om multitrådede systemer samtidig :)

#14
Jeg kigger lige på det.
Avatar billede Slettet bruger
07. august 2009 - 12:52 #18
#14
Kan du give et eksempel på anvendelsen af Invoke til mit formål?
Avatar billede windcape Praktikant
08. august 2009 - 15:48 #19
Invoke((Action)() => {
  // cross-threaded kode her
});
Avatar billede Slettet bruger
08. august 2009 - 15:51 #20
Hvordan lavede du den blå kodeboks? :)
Avatar billede Slettet bruger
08. august 2009 - 17:52 #21
delegate string EchoDelegate(string output);

public partial class MyForm : Form
{
public string Echo(string output)
{
return TextBox_Output.Text = Output += output + "\r\n";
}
}

class MyClass
{
MyForm Output; // Output sættes så til formen i den første tråd
void MyMethod(string output)
{
EchoDelegate ed = new EchoDelegate(Output.Echo);
ed.Invoke("Test");
}
}

Det virker ikke.
Avatar billede windcape Praktikant
10. august 2009 - 14:15 #22
public partial class MyForm : Form
{
    public TextBox Output
    {
        get { return TextBox_Output; }
        set { TextBox_Output = value; }
    }
}

class MyClass
{
    MyForm myForm;

    void MyMethod(string output)
    {
        myForm.Invoke((Action)() => {
            myForm.Output.Text = output;
        });
    }
}


benyt en DIV box til kode.
Avatar billede Slettet bruger
10. august 2009 - 15:07 #23

while (true)
Console.WriteLine("Infinite loop is infinite.");

<div>
while (true)
Console.WriteLine("Infinite loop is infinite.");
<div>
Avatar billede Slettet bruger
10. august 2009 - 15:07 #24
Tak :)
Og så lige en sidste test.

<div>
while (true)
Console.WriteLine("Infinite loop is infinite.");
</div>
Avatar billede Slettet bruger
11. august 2009 - 18:51 #25
Okaj, jeg er ikke helt sikker på, at jeg forstår det.

public partial class MyForm : Form
{
    public TextBox Output
    {
        get { return TextBox_Output; }
        set { TextBox_Output = value; }
    }
}


Hvorfor skal jeg selv erklære get og set?

class MyClass
{
    MyForm myForm;

    void MyMethod(string output)
    {
        myForm.Invoke((Action)() => {
            myForm.Output.Text = output;
        });
    }
}


Det ligner ikke noget, jeg har set før... Og slet ikke hvad jeg fandt frem til. Kan du evt. linke til uddybende stof?

Takker :)
Avatar billede windcape Praktikant
12. august 2009 - 00:42 #26
Som standard er GUI komponenter private, så det er pænest at expose dem du ønsker kan tilgåes cross-threaded, med en getter og setter.

Ideen er ikke så forskelligt fra din egen kode, forskellen er at jeg omgår alt det besværlige delegate kode, og benytter lambda expressions istedet.

Skal man lave et størrere projekt , så er det også en god ide at definere en Invoke der acceptere lambda, istedet for at typecast hvert enkelt expression.

public object Invoke<T>(Func<T> action)
{
    return Invoke((Delegate)action);
}
Avatar billede windcape Praktikant
12. august 2009 - 01:07 #27
Eksempel:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Threading;

namespace Lambda
{
    public partial class MyForm : Form
    {
        public MyForm()
        {
            InitializeComponent();
        }
       
        /// <summary>
        /// Executes the specified action on the thread that owns the control's underlying window handle.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="action">The action to be called in the control's thread context.</param>
        /// <returns>The return value from the action being invoked, or null if the action has no return value.</returns>
        public object Invoke(Action action)
        {
            return Invoke((Delegate)action);
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            Thread updateThread = new Thread(
                () => UpdateTime()
            );
            updateThread.Start();   
        }
       
        private void UpdateTime()
        {
            while(!this.IsDisposed)
            {
                Invoke(
                    () => clockTextBox.Text = DateTime.Now.ToString()
                );
               
                Thread.Sleep(1000); 
            }
        }
       
        #region Windows Form Designer generated code

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if(disposing && (components != null)) {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.clockTextBox = new System.Windows.Forms.TextBox();
            this.startButton = new System.Windows.Forms.Button();
            this.SuspendLayout();
            //
            // clockTextBox
            //
            this.clockTextBox.Location = new System.Drawing.Point(12, 12);
            this.clockTextBox.Name = "clockTextBox";
            this.clockTextBox.Size = new System.Drawing.Size(182, 20);
            this.clockTextBox.TabIndex = 0;
            //
            // startButton
            //
            this.startButton.Location = new System.Drawing.Point(200, 12);
            this.startButton.Name = "startButton";
            this.startButton.Size = new System.Drawing.Size(75, 20);
            this.startButton.TabIndex = 1;
            this.startButton.Text = "Start";
            this.startButton.UseVisualStyleBackColor = true;
            this.startButton.Click += new System.EventHandler(this.startButton_Click);
            //
            // MyForm
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(291, 42);
            this.Controls.Add(this.startButton);
            this.Controls.Add(this.clockTextBox);
            this.Name = "MyForm";
            this.Text = "MyForm";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        private System.Windows.Forms.TextBox clockTextBox;
        private System.Windows.Forms.Button startButton;       
       
        #endregion
    }
}
Avatar billede Slettet bruger
12. august 2009 - 14:12 #28
Hvor
        public object Invoke(Action action)
        {
            return Invoke((Delegate)action);
        }

og
                Invoke(
                    () => clockTextBox.Text = DateTime.Now.ToString()
                );

er de relevante kodestykker? Der er mange ting, jeg endnu ikke har arbejdet med i C#, så jeg er lidt langsom :)
Avatar billede windcape Praktikant
13. august 2009 - 05:48 #29
Korrekt. Og hvis du ikke er erfaren i lambda/linq kan det måske virke lidt langhåret ;)
Avatar billede Slettet bruger
13. august 2009 - 15:08 #30
Muligvis verdenshistoriens dummeste spørgsmål:
Hvad gør =>-operatoren, og hvorfor ()=>...?
Avatar billede Slettet bruger
13. august 2009 - 15:23 #31
Nu fik jeg det vist til at virke. Jeg har dog stadig et lille problem... Når brugeren lukker vinduet, aborter jeg arbejdstråden. Problemet er bare, at hvis tråden i samme øjeblik forsøger at skrive til vinduet - hvilket den altid gør, da aborten trigger en exception der så håndteres og meldes som fejl i vinduet - crasher hele møget med følgende fejl:
"Invoke or BeginInvoke cannot be called on a control until the window handle has been created."
Forslag?

PS: Jeg vil stadig gerne have svar på #30, hvis du da ikke er blevet træt af at svare uden for trådens oprindelige emne :)
Avatar billede Syska Mester
13. august 2009 - 18:44 #32
Nu er jeg også selv lidt ude på dybt vandt ...

Men det er lamda expressions ... de () er med fordi det hele ender ud i en operation og ingen assigment.

med Linq2Sql ... kan du gøre noget ala:

db.table.Select(a => a.ID);
som så returnere en IQueryable<T>

a'et er bare en henvisning til table ... som du så udføre noget på ...

Grunde til at det skal med "()" er nok at feltet ikke må være helt tomt ... og at det så bare angiver void ... kun en tanke.

Windcape .. ret mig gerne.
Avatar billede Slettet bruger
13. august 2009 - 19:33 #33
Jeg kan meddele, at jeg nu er 100 % lost :)
Avatar billede Syska Mester
13. august 2009 - 21:49 #34
Avatar billede windcape Praktikant
15. august 2009 - 17:09 #35
> Muligvis verdenshistoriens dummeste spørgsmål:
> Hvad gør =>-operatoren, og hvorfor ()=>...?

Forestil dig du har en List<T> med User objekter.
User er defineret som:

User { public int Age { get; set; } }


var users = new List<User>();


og vil så vil hente alle brugere som er ældre end 30 ud:

users.Select(user => user.Age > 30);


Her er 'user' en variabel i din lambda expression,
som representere det n'th. element i din liste.

dvs. svarende til følgende:

var user = users[n];
if(user.Age > 30) {
    return user;
}


> Jeg har dog stadig et lille problem...
> Når brugeren lukker vinduet, aborter jeg arbejdstråden

Fra mit eksempel:

while(!this.IsDisposed)


Hvis du laver et check på dit vindue's IsDisposed,
og så ikke invoker actions til det, hvis det er disposed,
så burde du undgå problemerne.
Avatar billede windcape Praktikant
15. august 2009 - 17:10 #36
Det skal så siges at overstående omkring lambda selector er meget uvidenskabeligt, samt at det kun giver mening for en liste.

Men en god forklaring til at starte med synes jeg.
Avatar billede windcape Praktikant
15. august 2009 - 17:13 #37
> Jeg kan meddele, at jeg nu er 100 % lost :)

Jeg kan meddele at resten at mit datamatiker hold er ligeså lost som dig :) (Indtil om et par måneder :p)

Det er en stor mundfuld, og et tungt emne. Men som du kan se, giver det noget ret læsbar kode, som virker ret smart og fornuftigt. Så det er værd at sætte sig ind i.
Avatar billede Slettet bruger
12. september 2009 - 17:57 #38
Hmm... Måske skulle man lukke tråden :) Jeg fandt i hvert fald ud af det.
Smid I bare nogle svar, hvis I vil.
Avatar billede Syska Mester
12. september 2009 - 19:58 #39
svar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester