2014年11月27日 星期四

[.NET] Lambda 中參考變數生命週期

Lambda,請念作浪打,就是希臘字母中的λ(波長) 不知道在那一代.NET體系後就出現了這個有趣的特性

簡單的說,Lambda-Expression是一種匿名函式的描述方式,我的習慣裡,通常配合Delegate一起服用(即時性的產生函式物件) 寫法長成這樣:

static Func delegateInstance = new Func(() => 
{
            Console.WriteLine("I was prisoned in Lambda!!!");
            return 0;
});
另外一個有趣的事情是,在CLR的記憶體模型中,
ByReference物件生命週期並不是離開函式Scope就消失,
 而是不再有人參考到此物件時,這飄渺在記憶體太空的虛無之物才會被GC回收,

所以可能會出現,在Lambda生成時,Lambda去參考函式局部範圍下的某個Object, 即便離開生成函式,一直到Lambda執行時,
這個Object仍然被保持住,而Lambda得以順利執行。
會有種 物件小姐 從 生成他的函式酒店 被"帶出場"的感覺(威~):


static int createLambda() 
{
            String theInstance = "I was created in createLambda()";
            delegateInstance = new Func(() => 
            {
                Console.WriteLine(theInstance.ToString());
                return 0;
            });

            return 0;
}
static int executeLambda()
{
            delegateInstance();
            return 0;
}
static void Main(string[] args)
{         
            createLambda();
            executeLambda();    //' theInstance still kept,  so that no NullReferenceException would raise
}

最後分享一個案例,若在Foreach中想要替陣列裡的每個物件創造對應的Lambda,在Lambda執行時,能反應陣列裡各物件的狀態(一個Lambda反應一個物件) 此時放在Lambda內的應該要用哪個具名參考?


  1. Iterator?
  2. 在Foreach外宣告一個參考? 
  3. 在Foreach內宣告參考?

       static void Main(string[] args)
        {         
          
            List theList = new List();
            Random rnd = new Random();

            Console.WriteLine("Peek answers");
            for (int i = 0; i < 10; i++)
            {
                myClass instance = new myClass();
                instance.myString = rnd.Next().ToString();
                theList.Add(instance);
                Console.WriteLine(instance.ToString());
            }
            Console.WriteLine("Peek over");


            delegateInstance = null;
            //myClass tempReference ;  //  option 2
            foreach (myClass item in theList)
            {
                //myClass tempReference = item;                       // option 3
                //tempReference = item;
                delegateInstance += new Func(() =>
                {
                    //Console.WriteLine(tempReference.ToString());
                    Console.WriteLine(item.ToString());                // option 1

                    return 0;
                });
            }

            Console.WriteLine("Lambda run");
            delegateInstance();                     // the invocation list
            Console.WriteLine("Lambda finish");

        }

答案是1、3都可(兩者效果等價),Foreach下的Reference在Iterator進到下一格時,會全部Refresh 所以各個Lambda內參考到的物件彼此是不相同的(連結到不同指標),即便程式碼中他們都是同名的變數。


 相反地,選項2用的Reference在Foreach外宣告,相當於只用一個指標去連結不同的物件 但Lambda們都是以同一個指標去參考物件,所以印出來的東西都是一樣的。

2014年11月15日 星期六

[.NET] TCP使用筆記1--物件序列化/反序列化傳送接收

將物件序列化後傳送串流 ------> 收到串流後反序列化還原物件

Import System.Runtime.Serialization.Formatters.Binary
<Serializable()>
Public Class MySerializableClass   ' Define a Class which is able to be serialized '
    Property s As String = "abcdedfg"
    Property i As Integer = 50
    Property f As Double = 3.14159256
End Class

Dim clientSend As TcpClient = New TcpClient()        'used to send stream'
Dim clientReceive As TcpClient = new TcpClient()     'used to receive stream'

Sub serializeAndSend()
   Dim bf As BinaryFormatter = New BinaryFormatter()             
   bf.Serialize(clientSend.GetStream(), New MySerializableClass())   ' Serialize object and write into net-stream '
End Sub

Function receiveAndDeserialize() As Object
   Dim bf As BinaryFormatter = New BinaryFormatter()             
   return bf.Deserialize(clientReceived.GetStream())   ' stream received and deserialize to object'
End Function

其中BinaryFormatter可用在任何串流的序列化/反序列化(檔案串流、網路串流、記憶體串流…等等) ,
可延伸此法將物件資料存入/讀出磁碟,比方機台參數設定...等等,或是做大型物件的記憶體內複製(應用記憶體串流)。

2014年11月8日 星期六

Windows網路橋接器 + Raspberri PI

筆記一下消耗我兩晚青春的Windows網路橋接器…

這次要搞定的拓樸結構長這樣:




目標是讓Raspberry PI 還有 筆電 都可以透過Wifi Router上網

首先先建立Windows網路橋接器,將筆電的Wifi介面與Ethernet介面橋接起來:


















橋接後照著原先的習慣,讓筆電連接Wifi,
並設定"自動取得IP",讓網路橋接器以DHCP協定向Router要到IP:






















Rasperry PI 這邊就要特別注意了,

必須手動設定 靜態IP、子網路遮罩、Gateway,
若以dhclient是要不到DHCPPACK的,因為透過網路橋接器發出的DHCPDISCOVER是以網路橋接器MAC為訊框,導致Router也一直將封包回錯對象,以至於Raspberry PI無法取得動態IP。
(檢查方法:查Router的 /var/log/syslog , 裡面的DHCP相關Log可以發現這個線索)

手動設定的方法如下:

#sudo vi /etc/network/interfaces           //編輯網路設定檔案

加入此行:
auto eth0
iface eth0 inet static
address 192.168.0.51 #注意要跟Router同網域,而且此IP未被其它人佔用
netmask 255.255.255.0network 192.168.0.254 #注意要跟Router同網域
broadcast 192.168.0.255 #注意要跟Router同網域
gateway 192.168.0.1     #可照著上圖的IPv4預設閘道設定

如此一來就沒問題了