2018年5月30日 星期三

Get value from JToken that may not exist (best practices)

width = jToken.Value<double?>("width") ?? 100;

from : https://stackoverflow.com/questions/9589218/get-value-from-jtoken-that-may-not-exist-best-practices

2018年5月17日 星期四

Dictionary that tells which key was not present

//Extended dictionary

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace Rextester
{
    public class MyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        public TValue this[TKey key]
        {
            get
            {
                TValue val;
                if(base.TryGetValue(key, out val))
                {
                    return val;
                }
                else
                {
                    throw new KeyNotFoundException(string.Format("The given key ({0}) was not present in the dictionary.", key));
                }
            }
            set
            {
                base[key] = value;
            }
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            //Dictionary<string, string> dic = new Dictionary<string, string>()
            //{
            //    {"a", "b"}
            //};
            MyDictionary<string, string> dic = new MyDictionary<string, string>()
            {
                {"a", "b"}
            };
           
            Console.WriteLine(dic["aa"]);
        }
    }
}

from : http://rextester.com/YKWBI65251

2018年5月15日 星期二

Ten tips to help you choose good names

There are only two hard things in Computer Science: cache invalidation and naming things.
Phil Karlton
Do you want to write great code? Clean, understandable, human-readable code? Well, there are several skills you need to acquire. But I’d say #1 on the list is “Picking Good Names”.
Choosing great names for your classes, methods, variables and the like is essential. Wisely chosen names often are the difference between good and awful code.
But what exactly is a good name? Even though there are some generally accepted guidelines, I’m afraid there isn’t a real consensus. (As it is with a lot of topics in our field, I’d say).
So, today I’m going to talk about naming conventions and principles that I try to use whenever I’m coding. It’s a mix of what I learned in college, studying by my own and working as a professional developer. It’s been useful to me, so I hope it’s going to be useful to you as well.
Some of the tips I’m going show you here today come from the book “Clean Code”, by Robert C. Martin (Uncle Bob). It’s one of my favorite programming books, and I’ll write a review on it sometime soon. Stay tuned!

0. Use self-explanatory names

What your variable/class/whatever does? How it’s supposed to be used? Choose a name that answers these questions.
Some people have the misguided notion that shorter names are always better. I can’t understand this. Are they trying to save keystrokes or something?
Let’s say you’re browsing a code base and you see some code like this:
    int d; // days until deadline
You could argue that this code is fine. The variable’s meaning is perfectly expressed in the comment. Great, but remember that the variable will probably be used in other points, away from the declaration and the comment.
So…why not just drop the comment and use the comment’s text as the variable’s name?
    int daysUntilDealine;

1. Use abbreviations only when they’re widely known

It would be crazy to name a variable “ServiceUniformResourceLocator” instead of “ServiceUrl”. Every developer knows what a Url is. The same thing with Ftp, UI, IO, and so on. So, it’s ok to use abbreviations to name things, but only if they are widely known and used. It would be counterproductive not to do so.
By the way. When I say “widely known”, I don’t necessarily mean worldwide known. Of course you can use abbreviations that are common in your business domain. It is considered a best practice to program as close as possible to the customer’s language. So, if your fellow developers and the business people are comfortable with the abbreviations, there’s no problem at all in using them.

2. Choose clarity over brevity

This is somewhat related to the first point. All else being equal, shorter names are better. But one day you’ll have to choose between clarity and brevity. When that day comes, always pick clarity. Six months down the road, when you have to revisit that code, you’re going to thank yourself.

3. Use widely accepted conventions (most of the time)

There are very few points in the book “Clean Code” that I disagree with. One of them is Uncle Bob’s recommendation to not start interface names with a capital “I”. He argues that this practice is reminiscent of Hungarian notation, and thus should die. Even though I understand why he thinks like this, I’m still starting my interface names with an “I”.
Why? One simple reason: starting interface names with an “I” is a very widespread and accepted convention in the .Net community. When you go against an established convention, you risk alienating developers who are used to that convention, like potential new team members or open-source projects contributors.
I think you should abandon a widely accepted convention only when the benefit of doing so greatly outweighs the costs. And I don’t think that’s the case here.

4. Don’t use Hungarian notation

Maybe you’ve heard about Hungarian Notation, maybe you haven’t. But I bet you’ve seen it, or even used it yourself, even if the name doesn’t ring a bell immediately.
So, what is this Hungarian thing? Our friend Wikipedia comes to our rescue:
Hungarian notation is an identifier naming convention in computer programming, in which the name of a variable or function indicates its type or intended use.
So, in a nutshell, Hungarian notation is encoding the type of the variable in its name. So, if I have an int variable meant to store the age of a student, I’d call it iStudentAge or intStudentAge. Similarly, a string variable supposed to store a product’s description would be called sProductDescription, or even strProductDescription.
And why is this bad? Here are a few reasons:
  • First of all, it’s useless. If your variable has a self-explaining name (see item #0), it will give you a decent clue about its type. If you spot a variable called productName, would you think it’s a floating-point number? Besides, most modern IDEs can tell you not only the variable’s type, but also if it’s a local variable,instance member or a method parameter, and even how many times it’s been referenced.
  • It can be misleading. People make mistakes, and it’s perfectly possible to change the variable’s type but forget to also change its name to reflect the new type. So now you have a variable prefixed with “int” but it’s actually a long.
  • It makes the names more difficult to pronounce, and this may complicate discussion about the code and the architecture of your application.

5. Stick to the language/framework/project’s coding style

Most C# developers tend to use CamelCase to name local variables, instance variables and methods parameters, as in productName. In Ruby, for instance, the recommended style is snake_case, as in product_name.
Development frameworks and open-source projects might have their own guidelines and standards as well.
It would be pointless to fight against established standards, due to a matter of taste and preference. If you’re writing Ruby code, write the way the Ruby community expects. The same with Java, C#, PHP, what have you.
It’s like they say: “When in Rome, do as the Romans do”.

6. Method names should start with a verb

This one is really short. Methods are usually actions that an object can perform. As such, their names should start with a verb that indicates the action to be performed, e.g. PrintReport()DrawShape(IShape shape).

7. Class names should be nouns

Likewise, class names should be nouns, like ProductCustomerStudent. Avoid using the words like ManagerData, because they add little or no value.

8. Property names should be nouns or adjective phrases (C# specific)

Properties should be names with nouns, noun phrases or adjectives. When naming boolean properties, you may add the prefixes CanIs or Has, when doing so provides value to the caller.

9. Use pronounceable/searchable names

Work hard to choose names that are pronounceable. When you pick a name that is hard or impossible to pronounce, you discourage discussion about your code, which is never a good thing.
Likewise, try to avoid names with a single letter. Among other reasons, they may give you a very hard time when you have to search for them! They make good names only for loop control variables or in lambda expressions. But even then, only when the scope is super short.

Conclusion

Choosing names is really hard. A name should express purpose, intention, meaning. It doesn’t necessarily need to be clever – but there are certain tricky situations that will require a little bit of cleverness.
A name should clearly express the purpose of the entity being named. But there are a lot of things that are very complex by their own nature, and it’s not so easy to come up with a perfect name for a very complex concept.
Sometimes, the difficulty you experience while choosing a name is a symptom of another problem, like a messy architecture, for instance. If you can’t decide between five options when naming a class, maybe the class is violating the Single Responsibility Principle (it’s trying to do more than one thing).
On the other hand, if you feel like calling a dozen classes the same thing…maybe they belong together as a single class.
Choosing names is ultimately about communication. And I think that’s why it’s such a hard task. Because we, developers, are not necessarily famous for our communication skills.
In “Clean Code”, at the end of the chapter about choosing good names, Uncle Bob writes:
The hardest thing about choosing good names is that it requires good descriptive skills and a shared cultural background. This is a teaching issue rather than a technical, business, or management issue. As a result, many people in this field do not do it very well.
Don’t be like most people in our field. Do the hard work and learn how to name things. You’ll thank yourself in the future.

from : http://carlosschults.net/en/how-to-choose-good-names/

[C#] 深層複製(Deep Clone)功能實作及應用

前言

有時候在操作物件時,某些物件只是做為 Template 使用,我們並不希望因為後續的操作而造成 Template 異動,因此會回傳複製品供取用者來使用;一方面確保 Template 物件絕不被異動,而另一方面則是避免取用者直接取用Tempalte物件時,不經意地透過相同物件參考位置而不小心同步變更資料源。

環境

  • .Net Framework 4.5
  • Json.Net 7.0.1

深層複製

稍微研究了一下深層複製方式後,發現約略有以下兩種方式;以下代碼皆以擴充方法(Extensions)進行實現,可以方便地讓所有物件都享有此功能。

使用BinaryFormatter複製

方式僅針對可序列化物件進行複製,也就是目標物件須標記 Serializable 標籤,否則是無法透過此方式執行 Deep Clone;因此先檢核目標物件是否為Serializable,若否將直接拋出錯誤,停止後續工作的進行。
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

public static class CommonExtensions
{

    /// <summary>
    /// 深層複製(複製對象須可序列化)
    /// </summary>
    /// <typeparam name="T">複製對象類別</typeparam>
    /// <param name="source">複製對象</param>
    /// <returns>複製品</returns>
    public static T DeepClone<T>(this T source)
    {

        if (!typeof(T).IsSerializable)
        { 
            throw new ArgumentException("The type must be serializable.", "source"); 
        }

        if (source != null)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(stream, source);
                stream.Seek(0, SeekOrigin.Begin);
                T clonedSource = (T)formatter.Deserialize(stream);
                return clonedSource;
            }
        }
        else
        { return default(T); }

    }
  
}

使用Json.Net複製

此方式是將物件序列化為Json格式後,再透過反序列化來反射出所需實體,因此複製對象若有循環參考(Self Reference)物件的情況存在時(ex. Entity Framework 的 navigation properties ),會造成序列化無限循環的錯誤發生;而針對此問題可以透過 PreserveReferencesHandling = PreserveReferencesHandling.Objects 設定讓Json.Net在序列化及反序列化時,將物件參考列入其中來避免無限循環參考問題發生。
using Newtonsoft.Json;

public static class CommonExtensions
{

    /// <summary>
    /// 深層複製(需使用Json.Net組件)
    /// </summary>
    /// <typeparam name="T">複製對象類別</typeparam>
    /// <param name="source">複製對象</param>
    /// <returns>複製品</returns>
    public static T DeepCloneViaJson<T>(this T source)
    {

        if (source != null)
        {
            // avoid self reference loop issue
            // track object references when serializing and deserializing JSON
            var jsonSerializerSettings = new JsonSerializerSettings
            {
                PreserveReferencesHandling = PreserveReferencesHandling.Objects,
                TypeNameHandling = TypeNameHandling.Auto
            };

            var serializedObj = JsonConvert.SerializeObject(source, Formatting.Indented, jsonSerializerSettings);
            return JsonConvert.DeserializeObject<T>(serializedObj, jsonSerializerSettings);
        }
        else
        { return default(T); }
     
    }
  
}

實例演練

假設有個 Utility 類別來提供遠端資料快取,由於測試方便所以在此就直接使用 static field 作為快取存放容器,其中 NotifySelections 存放的就是一個下拉式選單的項目清單,只設定Getter來避免取用端直接重新賦予新值,我們將以此作為下拉式選單Template資料源。
public class Utility
{

    // Fields
    private static List<SelectItem> _notifySelections;


    // Properties
    public static List<SelectItem> NotifySelections
    {
        get
        {
            if (_notifySelections == null)
            {
                _notifySelections = new List<SelectItem>
       {
        new SelectItem() { Name="Mail User", Value=1},
        new SelectItem() { Name="Call User", Value=2}
       };
            }

            return _notifySelections;
        }
    }

}

[Serializable]
public class SelectItem
{
    public string Name { get; set; }
    public int Value { get; set; }

    public override string ToString()
    {
        return string.Format("name:{0} weight:{1}", Name, Value);
    }
}

接著直接取用該資料源,並依照實際登入用戶來取代其中User文字 (ex. Mail User 改為 Mail Chirs),讓畫面上選單可以更貼近使用者感受;代碼如下圖所示,筆者會在取用Template資料物件且變更資料(2)前後,直接印出 Template 資料源物件資料(1)(3),我們可以來比較一下結果是否如預期。
class Program
{

    static void Main(string[] args)
    {
        // show cached NotifySelections
        Console.WriteLine("== Utility.NotifySelections ==");
        Console.WriteLine(GetContent(Utility.NotifySelections));
        

        // get selections as template
        var selections = Utility.NotifySelections;

        // replace some info
        foreach (var select in selections)
        { select.Name = select.Name.Replace("User", "Chris"); }

        // use it as drop down list items
        Console.WriteLine("== selections ==");
        Console.WriteLine(GetContent(selections));


        // show cached NotifySelections
        Console.WriteLine("== Utility.NotifySelections ==");
        Console.WriteLine(GetContent(Utility.NotifySelections));

    }

    // show items info
    static string GetContent<T>(List<T> items)
    {
        StringBuilder sb = new StringBuilder();
        foreach (var item in items)
        {  sb.AppendLine(item.ToString()); }

        return sb.ToString();
    }

}

結果出爐
  1. 正確取出 Template 選單資訊
  2. 正確取得並修改為所需之選單文字資訊
  3. 再次取出 Template 選單資訊時,已經被異動了!!!
來回顧一下,由於我們傳出的是物件參考,因此取用端取得的資料就是相同記憶體位置的同一份資料,因此所有的異動都會影響到作為 Template 物件的 _notifySelections 資料;這時就需要將 _notifySelections 進行深層複製,然後把複製品傳出,最終取用端要如何操作該物件都將不再影響資料源。
調整後將以下列方式進行深層複製且回傳取用端
_notifySelections.DeepClone() 或 _notifySelections.DeepCloneViaJson()
最後看一下結果
  1. 正確取出 Template 選單資訊
  2. 正確取得並修改為所需之選單文字資訊
  3. 正確取出 Template 選單資訊,未再被異動了。

參考資訊


from : https://dotblogs.com.tw/wasichris/2015/12/03/152540