csharp-and-dotnet

Visual Studio External Tools

posted on 08 Feb 2007 18:04 by tidno1 in csharp-and-dotnet

วันนี้ขอแนะนำวิธีการสะดวกสบายสำหรับคนใช้ Visual Studio ซะหน่อย
สิ่งที่จะมาแนะนำวันนี้คือการเรียกโปรแกรมอื่นผ่าน Visual Studio

หลาย ๆ คนคงเคยแหละ เวลาเขียนโปรแกรมอยู่ แล้วเกิดอยากเปิด notepad ขึ้นมาเก็บ code บางส่วนไว้, เปิด calculator มาทดเลข หรือต้องใช้ tool ต่าง ๆ ของ .NET SDKขขข การจะไปเรียก shortcut หรือพิมพ์ command ในหน้าต่างรันบางทีมันก็ไม่สะดวก เรามาใช้สิ่งที่ VS เตรียมไว้ให้ดีกว่า

ขั้นแรก ไปที่เมนู Tools -> External Tools... ตามรูปนี้เลย

แล้วหลังจากนั้นก็กดปุ่ม Add เพื่อใส่ tool อื่น ๆ เข้าไป

  1. แล้วก็พิมพ์ชื่อที่ต้องการแสดงในเมนูที่ช่อง Title
  2. ใส่ full path ของโปรแกรมลงไปในช่อง command ย้ำนะครับว่าต้อง full path เท่านั้น
  3. ถ้าโปรแกรมที่จะรันต้องการ argument ก็ใส่เรียงไปได้ใ่นช่อง argument เลย argument ต้องใส่ช่องนี้นะ ใส่ต่อท้าย path ของ command ไม่ได้ ส่วนปุ่มข้าง ๆ เนี่ย เดี๋ยวจะบอกให้ว่าใช้อะไร
  4. Initial directory นี่ไม่แน่ใจว่าไว้ใส่อะไร ขอติดไว้ก่อน

ตัวอย่างเช่นผมจะใส่ IL Disassembler ก็จะใส่ path C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\ildasm.exe ลงไปในช่อง Command แล้วก็กด OK เป็นที่เรียบร้อย

ซึ่งปกติผมก็มักจะใช้ IL DASM เพื่อดู IL ของ assembly ปัจจุบัน (โปรเจคท์ปัจจุบัน) ก็แค่ใส่ argument ของ command เป็น Target Path ซะ

อย่างของผมนี่ก็จะใส่ลงไปแบบนี้

เมื่อใส่ทั้งหมดลงไปแล้ว tool เหล่านี้ก็จะไปปรากฎภายใต้เมนู Tools

อาจจะแปลกใจนิดหน่อยว่าผมใช้ IL DASM เยอะมาก ส่วนใหญ่ผมไว้สำหรับอ้างอิงตอนคุยกับคนอื่น ว่าเขียน code แบบไหนดีไม่ดี เรียก method ตัวไหนถึงจะเหมาะกว่ากัน
เดี๋ยวคราวหน้าจะใช้ประโยชน์จาก IL DASM นี้ให้คุ้มกันล่ะ

หลาย ๆ คนคงได้ใช้ .NET 2.0 กันพอสมควรแล้ว น่าจะได้เห็น API ที่เพิ่มเข้ามาใหม่มากมาย

ใน class Array นั้นมี static method ใหม่ ๆ เพิ่มเข้ามามาก และส่วนใหญ่ก็จะเป็น generic method แล้วบาง method นั้นก็รับ parameter เป็น generic delegate ใหม่ ๆ เช่น
public static TOutput[] ConvertAll<TInput,TOutput>(TInput[], Converter<TInput, TOutput>);
public static T[] FindAll<T>(T[], Predicate<T>);
public static void ForEach<T>(T[], Action<T>);
public static bool TrueForAll<T>(T[], Predicate<T>);
เห็น parameter type แล้วคงงง parameter ตัวหลังนั้นคือ generic delegate ครับ ลองดู signature กัน
public delegate void Action<T>(T);
public delegate TOutput Converter<TInput,TOutput>(TInput);
public delegate bool Predicate<T>(T);

ครับ Predicate ก็คือ method ที่คอยตรวจสอบค่า parameter ว่าเป็นค่าที่เราต้องการหรือไม่
ส่วน Action ก็คือ method ที่นำ parameter ไปทำอะไรซักอย่าง

ทีนี้ลองมาดูการใช้งาน method เหล่านี้กัน

void MyMethod() {
    Color[] pixels = GetPixels();
    // C# 2.0 allow you do not need to create the delegate explicitly
    // Color[] shadows = Array.FindAll(pixels, new Predicate(IsShadow));
    Color[] shadows = Array.FindAll(pixels, IsShadow);
    int[] argb = Array.ConvertAll(shadows, ToArgb);

}

bool IsShadows(Color c) {
    return (c.R + c.G + c.B) / 3 < 96;
}

int ToArgb(Color c) {
    return c.ToArgb();
}
void SomeMethod() {
    int[] nums = GetErrorCode();
    int[] negativeVals = ArrayFindAll(nums, IsNegative);
    Array.ForEach(negativeVals, WriteLog);
}

bool IsNegative(int n) {
    return n < 0;
}

void WriteLog(int n) {
    Trace.WriteLine(n);
}
bool ValidateAddresses() {
    TextBox[] txtAddresses = GetAddresses();
    return Array.TrueForAll(txtAddresses, HasText);
}

bool HasText(TextBox txt) {
    return txt.TextLength > 0;
}

จะเห็นได้ว่าเราต้องเปลืองที่มาเขียน method สั้น ๆ ที่ไม่ได้ทำอะไรซักเท่าไหร่ เพื่อให้สามารถส่งไปเป็น parameter ของ method นั้นได้ (ตัวอย่างอาจดูงี่เง่าไปนิดหน่อย ก็อย่าไปสนใจมันเลยเนอะ)

ทีนี้ถ้าเราเอา anonymous method มาช่วยลดความยุ่งยากลง ก็จะได้ดังนี้

void MyMethod() {
    Color[] pixels = GetPixels();
    Color[] shadows = Array.FindAll(pixels, delegate(Color c) { return (c.R + c.G + c.B) / 3 < 96; });
    int[] argb = Array.ConvertAll(shadows, delegate(Color c) { return c.ToArgb(); });
}
void SomeMethod() {
    int[] nums = GetErrorCode();
    int[] negativeVals = ArrayFindAll(nums, delegate(int n) { return n < 0;});
    Array.ForEach(negativeVals, delegate(int n) { Trace.WriteLine(n); });
}
bool ValidateAddresses() {
    TextBox[] txtAddresses = GetAddresses();
    return Array.TrueForAll(txtAddresses, delegate(TextBox txt) { return txt.TextLength > 0; });
}
---------------------------------- แถม ----------------------------------
ถ้าเขียนด้วย lambda expression ใน C# 3.0 จะำได้ code ที่สั้นลงไปอีก
void MyMethod() {
    Color[] pixels = GetPixels();
    Color[] shadows = Array.FindAll(pixels, c => (c.R + c.G + c.B) / 3 < 96);
    int[] argb = Array.ConvertAll(shadows, c => c.ToArgb());
}
void SomeMethod() {
    int[] nums = GetErrorCode();
    int[] negativeVals = ArrayFindAll(nums, n => n < 0);
    Array.ForEach(negativeVals, n => Trace.WriteLine(n));
}
bool ValidateAddresses() {
    TextBox[] txtAddresses = GetAddresses();
    return Array.TrueForAll(txtAddresses, txt => txt.TextLength > 0);
}

Covariance and Contravariance in Delegates

posted on 01 Oct 2006 01:05 by tidno1 in csharp-and-dotnet
คงเคยใช้ delegate กันมาบ้างใช่มั้ยครับ ลองมารู้จักกับศัพท์แปลก ๆ กันซักสองคำ

Covariance

covariance คือการที่ return type ของ method นั้น specific มากกว่า (derive มาจาก) return type ของ delegate นั้น
class Shape { }

class Polygon : Shape { }

class Program {
    public delegate Shape ConstructCallback();

    public Shape Construct1() {...}

    public Polygon Construct2() {...}

    static void Main() {
        ConstructCallback handler1 = Construct1;

        // Covariance allows this delegate.
        ConstructCallback handler2 = Construct2;
    }
}

Contravariance

contravariance คือการที่ method มี parameter ที่เป็น base type ของ parameter ใน delegate ตัวนั้น ๆ
class Shape { }

class Polygon : Shape { }

class Program {
    public delegate void RenderCallback(Polygon);

    public void Render1(Shape s) {...}

    public void Render2(Polygon p) {...}

    static void Main() {
        // Contravariance permits this delegate.
        RenderCallback handler1 = Render1;

        RenderCallback handler2 = Render2;
    }
}