To generate random numbers

To generate random numbers:


public class TestClass
{
  private RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider();
  private byte[] _uint32Buffer = new byte[4];

  public int RandomNext(int min, int max)
  {
    if (min >= max)
    {
      return min;
    }

    long diff = max + 1 - min;

    while (true)
    {
      _rng.GetBytes(_uint32Buffer);
      uint rand = BitConverter.ToUInt32(_uint32Buffer, 0);

      long lMax = (1 + (long)uint.MaxValue);
      long remainder = lMax % diff;

      if (rand < lMax - remainder)
      {
        return (int)(min + (rand % diff));
      }
    }
  }

  private void ToTest()
  {
    StringBuilder log = new StringBuilder();
    for (int i = 0; i < 1000; i++)
    {
      log.Append(RandomNext(0, 1)).AppendLine();
    }

    WriteLog(log.ToString());
  }
}

 
“Since the numerator is the only place that we can introduce randomness, and since a Double is 64 bits long, rather than generating a UInt32 and dividing by UInt32.MaxValue+1, we could try generating a random UInt64 and dividing by UInt64.Max + 1, thereby doubling the amount of random bits in the input.
This, unfortunately, leads to another problem. Double-precision numbers store an approximation of a real number; System.Double, which complies with the IEEE 754 standard for binary floating-point arithmetic, provides at most 17 decimal digits of precision. Unfortunately, UInt64.MaxValue (18446744073709551615) requires 20 decimal digits of precision. As a result, under .NET floating-point arithmetic, UInt64.MaxValue is equal to UInt64.MaxValue + 1, and, thus, substituting UInt64 for UInt32 in our NextDouble equation will change our range from [0.0, 1.0) to [0.0, 1.0], which violates the design of System.Random’s implementation."

“For an example that demonstrates this skewing, let’s say we want a number in the range [21, 27]. (For this example, we’ll be selecting 8 bits rather than 32 bits just because it’s easier for demonstration, but the principle generalizes out to the 32 bits we’d actually be working with.) Following the equation shown earlier, we’ll now take a random number between 0 and 255 mod 6 + 21 to get our value. If the random number is in the range [0, 251] this works out great as each of the numbers [0,5] has come up exactly 42 times. However, once we move past 251, we’ll get 0 (252), 1 (253), 2 (245), and 3 (255) as values from our mod operation. That means that 0, 1, 2, and 3 have a 43/256 chance of being selected by the mod operation while 4 and 5 only have a 42/256 chance. Therefore, we’ve got a ~16.80 percent chance of getting 21, 22, 23, or 24 back, but only a ~16.41 percent chance of getting 25 or 26 back. Over the long term, if we were an attacker trying to guess outputs, we would be more successful by always choosing a number at the low end of the range."

“As we saw in the previous example, the favoritism happens when the randomly selected value satisfies the following condition:


RandomValue >= RandomRange - (RandomRange % TargetRange)

In our previous example, the RandomRange is 256 and the TargetRange is 6; therefore, favoritism happens when the RandomValue is >= 252."

 
Reference:

1) .NET Matters: Tales from the CryptoRandom https://docs.microsoft.com/en-us/archive/msdn-magazine/2007/september/net-matters-tales-from-the-cryptorandom

2) Buffered CryptoRandom implementation based on Stephen Toub and Shawn Farkas’ CryptoRandom https://gist.github.com/niik/1017834

3) RNGCryptoServiceProvider – generate number in a range faster and retain distribution? https://stackoverflow.com/questions/6299197/rngcryptoserviceprovider-generate-number-in-a-range-faster-and-retain-distribu

4) How do I generate a random int number? https://stackoverflow.com/questions/2706500/how-do-i-generate-a-random-int-number

 

TVP in SQL Server

Table-Valued Parameters (TVP) in SQL Server:

1. Create Type [TVP_Int]:


USE [DB01]
GO

CREATE TYPE [dbo].[TVP_Int] AS TABLE(
    [Val] [int] NOT NULL,
    PRIMARY KEY CLUSTERED 
    (
        [Val] ASC
    )WITH (IGNORE_DUP_KEY = OFF)
)
GO

 

SSMS : programmability => Types => User-Defined Table Types;

 
2. Stored Procedure:


CREATE PROCEDURE [dbo].[List_TestInfo] 
  @IDs As TVP_Int Readonly

AS
BEGIN

  SET NOCOUNT ON;

  SELECT 
    ID, Name 
  FROM
    TestInfo WITH(NOLOCK) 
  WHERE 
    ID IN (SELECT Val FROM @IDs)

END

 

3. Test SP:


DECLARE @Tbl AS [TVP_Int];
INSERT INTO @Tbl (Val) VALUES (1001)
INSERT INTO @Tbl (Val) VALUES (1002)
INSERT INTO @Tbl (Val) VALUES (1003)

EXEC [List_TestInfo]
    @IDs = @Tbl 

 

4. (C#) Convert SqlParameter (List to DataTable):


private DataTable ToDataTable<T>(List<T> list)
{
  DataTable t = new DataTable();
  t.Columns.Add("Val", typeof(T));

  foreach (var i in list)
  {
    t.Rows.Add(i);
  }

  return t;
}

 

Reference:

1) SQL 2008 TVP資料匯入之火力展示 https://blog.darkthread.net/blog/import-with-sql-tvp
2) SqlBulkCopy Vs. TVP Vs. XML Parameter Vs. Individual Insert Procs for 20-200 Inserts? https://stackoverflow.com/questions/8618261/sqlbulkcopy-vs-tvp-vs-xml-parameter-vs-individual-insert-procs-for-20-200-ins
3) Table-Valued Parameters https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/table-valued-parameters

 

API response caching

API response caching:


public class CacheBase
{
  protected int _expireDuration;
  protected long _cacheTimestamp;

  public int KeyMaxCount { get; set; }
  public dynamic SingleData { get; set; }
  public List<dynamic> ListOfData { get; set; }

  public CacheBase()
  {
    KeyMaxCount = 2000;
  }

  public bool IsExpire()
  {
    if (CurrentTimestamp() - _cacheTimestamp < _expireDuration)
    {
      return false;
    }

    return true;
  }

  protected long CurrentTimestamp()
  {
    return (long)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
  }
}

 


public class Person
{
  public int ID { get; set; }
  public string Name { get; set; }
}

public class PersonCache : CacheBase
{
  public PersonCache(List<Person> dataList)
  {
    _expireDuration = 20;
    _cacheTimestamp = CurrentTimestamp();

    if (dataList != null)
    {
      DataList = dataList.Cast<dynamic>().ToList();
    }
  }
}

 


protected bool IsCacheExpire<U>(ConcurrentDictionary<string, U> cacheDict, string key, out U cache)
	where U : CacheBase
{
  cache = default(U);
  if (cacheDict.TryGetValue(key, out cache) && cache != null
    && !cache.IsExpire())
  {
    return false;
  }

  if (cache != null && cacheDict.Count > cache.KeyMaxCount)
  {
    CleanCache(cacheDict);
  }

  return true;
}

protected void CleanCache<U>(ConcurrentDictionary<string, U> cacheDict)
  where U : CacheBase
{
  if (cacheDict == null || cacheDict.Count == 0)
  {
    return;
  }

  NLog.Logger logger = NLog.LogManager.GetLogger("CleanCache");
  StringBuilder log = new StringBuilder();

  try
  {
    LogCache(cacheDict, ref log);

    U got;
    foreach (var cache in cacheDict)
    {
      if (cache.Value != null && cache.Value.IsExpire())
      {
        cacheDict.TryRemove(cache.Key, out got);
      }
    }

    log.AppendLine("[After clean]");
    LogCache(cacheDict, ref log);
    logger.Info(log.ToString());
  }
  catch (Exception ex)
  {
    logger.Error(ex, log.ToString());
  }
}

protected void LogCache<U>(ConcurrentDictionary<string, U> cacheDict, ref StringBuilder log)
{
  if (cacheDict == null || cacheDict.Count == 0)
  {
    return;
  }

  log.AppendFormat("Cache Count: {0}", cacheDict.Count).AppendLine();
  log.Append("Keys: ");
  foreach (var cache in cacheDict)
  {
    log.AppendFormat("{0},", cache.Key);
  }
  log.AppendLine();
}

protected void AddNewCache<T>(ConcurrentDictionary<int, T> cacheDict, int key, T data)
{  //To reset the Cache Timestamp.
  T cache;
  if (cacheDict.TryGetValue(key, out cache))
  {
    cacheDict.TryRemove(key, out cache);
  }
  cacheDict.TryAdd(key, data);
}

 


private static ConcurrentDictionary<int, PersonCache> _personCacheDict = new ConcurrentDictionary<int, PersonCache>();

public List<Person> GetPeople(int keys)
{

  #region Query from cache

  uncachedKeys = new List<int>();
  List<Person> rtn = new List<Person>();

  foreach (int key in keys)
  {
    PersonCache cache;
    if (!IsCacheExpire<PersonCache>(_personCacheDict, key, out cache) 
      && cache.DataList != null)
    {
      cache.DataList.ForEach(data => rtn.Add(data));
    }
    else
    {
      uncachedKeys.Add(key);
    }
  }

  #endregion

  #region Query from db

  List<Person> dbDataList = QueryFromDB(uncachedKeys);

  if (dbDataList.Count == 0)
  {
    return rtn;
  }

  #endregion

  #region Write into the cache

  foreach (int key in uncachedKeys)
  {
    List<Person> list = (from p in dbDataList where p.ID == key select p).ToList();
    AddNewCache(_personCacheDict, key, new PersonCache(list));
  }

  #endregion

  return rtn.AddRange(dbDataList);
}

 

.NET DateTime

.NET DateTime:


StringBuilder log = new StringBuilder();

log.Append("DateTime.Now:\t").Append(DateTime.Now).AppendLine();
log.Append("DateTime.UtcNow:\t").Append(DateTime.UtcNow).AppendLine().AppendLine();

log.Append("DateTime.Now.ToLocalTime():\t").Append(DateTime.Now.ToLocalTime()).AppendLine();
log.Append("DateTime.UtcNow.ToLocalTime():\t").Append(DateTime.UtcNow.ToLocalTime()).AppendLine().AppendLine();

log.Append("DateTime.Now.ToUniversalTime():\t").Append(DateTime.Now.ToUniversalTime()).AppendLine();
log.Append("DateTime.UtcNow.ToUniversalTime():\t").Append(DateTime.UtcNow.ToUniversalTime()).AppendLine().AppendLine();

log.Append("new DateTime(2019,5,1,0,0,0,0):\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, 0)).AppendLine();
log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Unspecified):\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Unspecified)).AppendLine().AppendLine();

log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Local):\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Local)).AppendLine();
log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Local).ToLocalTime():\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Local).ToLocalTime()).AppendLine();
log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Local).ToUniversalTime():\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Local).ToUniversalTime()).AppendLine().AppendLine();

log.Append("new DateTime(2019,5,1,0,0,0,0).ToLocalTime():\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, 0).ToLocalTime()).AppendLine();
log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Unspecified).ToLocalTime():\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Unspecified).ToLocalTime()).AppendLine().AppendLine();

log.Append("new DateTime(2019,5,1,0,0,0,0).ToUniversalTime():\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, 0).ToUniversalTime()).AppendLine();
log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Unspecified).ToUniversalTime():\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Unspecified).ToUniversalTime()).AppendLine().AppendLine();

log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Utc):\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Utc)).AppendLine();
log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Utc).ToLocalTime():\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime()).AppendLine();
log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Utc).ToUniversalTime():\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Utc).ToUniversalTime()).AppendLine().AppendLine();

WriteLog(log.ToString());

 

Result:

Snipaste_2019-05-16_19-29-29

Snipaste_2019-05-17_18-04-26.png

 

 

Static member in C#

Static members in different objects from the same type refer to the same reference.


public class Obj
{
  private static string _static { get; set; }

  public string StaticValue 
  {
    get { return _static; }
    set { _static = value; }
  }
}


private void Test()
{
  StringBuilder log = new StringBuilder();

  Obj obj_1 = new Obj();
  obj_1.StaticValue = "1";

  WriteLog(string.Format("obj_1: {1}{0}", Environment.NewLine, obj_1.StaticValue));

  Obj obj_2 = new Obj();
  obj_2.StaticValue = "2";

  WriteLog(string.Format("obj_1: {1}, obj_2: {2}{0}", Environment.NewLine, obj_1.StaticValue, obj_2.StaticValue));

  Obj obj_3 = new Obj();
  obj_3.StaticValue = "3";

  WriteLog(string.Format("obj_1: {1}, obj_2: {2}, obj_3: {3}{0}", Environment.NewLine, obj_1.StaticValue, obj_2.StaticValue, obj_3.StaticValue));

  return;
}

 

Result:

Snipaste_2019-05-13_17-33-40.png

 

Deep Copy in C#

Deep Copy in C#:

1) Shallow Copy:

For a reference type, the clone refer to the same memory address.

1.1) Shallow Copy about object:

Snipaste_2019-04-18_15-41-48

 
1.2) Shallow Copy about Dictionary:

Snipaste_2019-04-18_15-37-06

 
1.3) Shallow Copy an array:


Person[] newArr = arr;

 

2) Deep Copy:

For a reference type, the clone refer to a new memory address.

2.1) Deep Copy an array:


public class Person
{
  public int Age { get; set; }
  public string Name { get; set; }

  public Person Clone()
  {
    Person p = new Person();
    p.Age = this.Age;
    p.Name = this.Name;

    return p;
  }
}

 


List<Person> list = new List<Person>();

//Can't modify an array within foreach.
for (int i = 0; i < arr.Length; i++)
{
  list.Add(arr[i].Clone());
}
Person[] newArr = list.ToArray();

 

2.2) Deep Copy using JSON Serialization:


/// <summary>
/// Deep Copy (Private members are not cloned using this method.)
/// </summary>
public static T CloneJson<T>(this T source)
{            
  if (Object.ReferenceEquals(source, null))
  {
    return default(T);
  }

  // initialize inner objects individually
  // for example in default constructor some list property initialized with some values,
  // but in 'source' these items are cleaned -
  // without ObjectCreationHandling.Replace default constructor values will be added to result
  var deserializeSettings = new JsonSerializerSettings {ObjectCreationHandling = ObjectCreationHandling.Replace};

  return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}

 

 

Reference:

1. [C#.NET] 淺複製與深複製 https://dotblogs.com.tw/yc421206/archive/2011/06/17/28785.aspx

2. Deep cloning objects https://stackoverflow.com/questions/78536/deep-cloning-objects/78612#78612

3. Fast array copy in C# https://stackoverflow.com/questions/23248872/fast-array-copy-in-c-sharp?lq=1

4. Modify array with Array.Foreach and lambda expression https://stackoverflow.com/questions/17037459/modify-array-with-array-foreach-and-lambda-expression

5. How to delete an element from an array in C# https://stackoverflow.com/questions/496896/how-to-delete-an-element-from-an-array-in-c-sharp

6. C# List<T>.ToArray performance is bad? https://stackoverflow.com/questions/1147497/c-sharp-listt-toarray-performance-is-bad

7. .NET data structures: ArrayList, List, HashTable, Dictionary, SortedList, SortedDictionary — Speed, memory, and when to use each? https://stackoverflow.com/questions/128636/net-data-structures-arraylist-list-hashtable-dictionary-sortedlist-sorted

8. In .NET, which loop runs faster, ‘for’ or ‘foreach’? https://stackoverflow.com/questions/365615/in-net-which-loop-runs-faster-for-or-foreach/365658#365658

 

.NET Remoting and WCF

.NET Remoting and Windows Communication Foundation (WCF):

.NET Remoting
  (not recommended)

WCF

Platform required
Microsoft OS and .NET Only Cross-platform
Data model
   & Interface Library (for Reference)
By-value types in Remoting are marked with the [Serializable] attribute or implement ISerializable: Create classes marked with the [DataContract] attribute.
The individual properties we want visible to both client and server are marked with [DataMember].
If we want derived types to be allowed, we must use the [KnownType] attribute to identify them.

[Serializable]  
public class Customer  
{  
  public string FirstName { get; set; }

  public string LastName { get; set; }

  public int CustomerId { get; set; }
}


[DataContract]  
[KnownType(typeof(PremiumCustomer))]  
public class Customer  
{  
  [DataMember]  
  public string FirstName { get; set; }  

  [DataMember]  
  public string LastName { get; set; }  

  [DataMember]  
  public int CustomerId { get; set; }  
}  

[DataContract]  
public class PremiumCustomer : Customer   
{  
  [DataMember]  
  public int AccountId { get; set; }  
}

The public methods of this server type become the public contract available to clients. Define a public interface and mark it with the [ServiceContract] attribute.
Methods available to clients are marked with [OperationContract].

public interface ICustomerService  
{  
  Customer GetCustomer(int customerId);  
}


[ServiceContract]  
public interface ICustomerService  
{  
  [OperationContract]  
  Customer GetCustomer(int customerId);  

  [OperationContract]  
  bool UpdateCustomer(Customer customer);  
}

[Server] Define public methods
.NET Remoting server types must derive from MarshalByRefObject. WCF:

public class CustomerService 
    : MarshalByRefObject, ICustomerService 
{  
  public Customer GetCustomer(int customerId)
  {
  }

  public override Object InitializeLifetimeService()
  {
    //Let MarshalByRefObject 
    // never expire.
    return null;
  }
}


public class CustomerService 
    : ICustomerService  
{  
  public Customer GetCustomer(int customerId)  
  {  
  }  

  public bool UpdateCustomer(Customer customer)  
  {  
  }  
}

[Server] Start the Server service
.NET Remoting: Declare an endpoint that exposes that service interface at a specific URL using a specific WCF binding.

TcpChannel channel = new TcpChannel(8000);  
ChannelServices.RegisterChannel(
  channel, 
  ensureSecurity : true);
RemotingConfiguration.RegisterWellKnownServiceType(  
  typeof(CustomerService),   
  "CustomerService",   
  WellKnownObjectMode.Singleton);


NetTcpBinding binding = new NetTcpBinding();  
Uri baseAddress = new Uri("net.tcp://localhost:8000/CustomerService");  
  
using (ServiceHost serviceHost = new ServiceHost(
    typeof(CustomerService), baseAddress))  
{  
  serviceHost.AddServiceEndpoint(
    typeof(ICustomerService), 
    binding, 
    baseAddress);  
  serviceHost.Open();  
}

[Client] Implementation
The CustomerService instance returned from Activator.GetObject() is known as a “transparent proxy". Use a channel factory to create the proxy explicitly.
Like Remoting, the proxy object can be used to invoke operations on the server.
The channel implements the service’s interface and handles the underlying request/reply logic.

TcpChannel channel = new TcpChannel();  
ChannelServices.RegisterChannel(
  channel, 
  ensureSecurity : true);
CustomerService server = (CustomerService)Activator.GetObject(  
  typeof(CustomerService),   
  "tcp://localhost:8000/CustomerService");  
  
Customer customer = server.GetCustomer(42);  

Console.WriteLine($"Customer {customer.FirstName} {customer.LastName} received.");


NetTcpBinding binding = new NetTcpBinding();  
String url = "net.tcp://localhost:8000/CustomerService";  
EndpointAddress address = new EndpointAddress(url);  

ChannelFactory channelFactory =   
  new ChannelFactory(binding, address);  
ICustomerService server = channelFactory.CreateChannel();  
  
Customer customer = server.GetCustomer(42);  

Console.WriteLine($"  Customer {customer.FirstName} {customer.LastName} received.");

Scenario: Client: Sends Server a By-Value Instance

ChannelFactory factory =  
  new ChannelFactory("customerservice");  
ICustomerService service = factory.CreateChannel();  
PremiumCustomer customer = new PremiumCustomer {   
  FirstName = "Bob",   
  LastName = "Jones",   
  CustomerId = 43,   
  AccountId = 99};  
bool success = service.UpdateCustomer(customer);  

Console.WriteLine($"  Server returned {success}.");

Reference:
1) 從 .NET 遠端處理移轉到 WCF https://docs.microsoft.com/zh-tw/dotnet/framework/wcf/migrating-from-net-remoting-to-wcf
2) 閒談:.NET Remoting、WCF、WebAPI、Socket,該怎麼選? https://blog.darkthread.net/blog/remoting-wcf-webapi-choice

Remove item from list in C#

Remove item from list in C#:


public partial class Form1 : Form
{
  private System.Threading.Timer timer1 = null;
  private List list1 = null;

  public Form1()
  {
    list1 = new List();
  }

  private void button1_Click(object sender, EventArgs e)
  {
    if (timer1 == null)
    {
      //Call Method1 after 3 seconds.
      timer1 = new System.Threading.Timer(
        new System.Threading.TimerCallback(CallbackMethod1),  //callback deletage.
        string.Empty,  //state.
        3000,  //dueTime.
        0);  //period.
    }
  }

  private void CallbackMethod1(object obj)
  {
    string key = string.Format("{0:ss}", DateTime.UtcNow);
    list1.Add(
      new class1()
      {
        Dict = new ConcurrentDictionary() {{ key, string.Empty }}
      }
    );

    if (list1.Count > 4)
    {
      list1[0].Dispose();
      //Remove the reference of the first element.
      list1.RemoveAt(0);
    }

    //Call Method1 every 7 seconds.
    timer1.Change(
      7000,  //dueTime.
      System.Threading.Timeout.Infinite);  //period.
    //The same: timer1 = new System.Threading.Timer(new System.Threading.TimerCallback(CallbackMethod1), string.Empty, 7000, 0);
  }
}

public class class1 : IDisposable
{
  public ConcurrentDictionary Dict { get; set; }

  public void Dispose()
  {
    Dict.Clear();
  }
}

 

Result:

Snipaste_2019-03-20_14-21-26

 

Reference:

Timer.Change Method https://docs.microsoft.com/zh-tw/dotnet/api/system.threading.timer.change?view=netframework-4.7.2

 

Boolean.TryParse in C#

Boolean.TryParse in C#:


StringBuilder log = new StringBuilder();

log.Append("when default = false: ").AppendLine();
new List() { null, string.Empty, " 1 ", "1", 
    " true ",  " True ", " TRue ", " TRUE "}
  .ForEach(str =>
    {
      bool result = false;
      bool.TryParse(str, out result);
      log.AppendFormat("\"{0}\"\t-->\t{1}", str, result).AppendLine();
    });

log.AppendLine().Append("when default = true: ").AppendLine();
new List() { null, string.Empty, " 0 ", "0", 
    " false ",  " False ", " FalSe ", " FALSE "}
  .ForEach(str => 
    {
      bool result = true;
      bool.TryParse(str, out result);
      log.AppendFormat("\"{0}\"\t-->\t{1}", str, result).AppendLine();
    });

WriteLog("Test", log.ToString());

 

Result:

Snipaste_2019-03-21_16-17-23

 

Reference:
Boolean.TryParse Method https://docs.microsoft.com/zh-tw/dotnet/api/system.boolean.tryparse?view=netframework-4.7.2

C# Operator Precedence

C# Operator Precedence:

C# Operator Precedence (from highest to lowest)

Category Operators
Postfix Increment and Decrement ++, —
Prefix Increment, Decrement and Unary ++, –, +, -, !, ~
Multiplicative *, /, %
Additive +, –
Shift <<, >>
Relational <, <=, >, >=
Equality ==, !=
Bitwise AND &
Bitwise XOR ^
Bitwise OR |
Logical AND &&
Logical OR ||
Ternary ? :
Assignment =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=

 

Snipaste_2019-03-12_15-04-57

Snipaste_2019-03-12_15-05-52

 

Reference:

C# Operator Precedence and Associativity https://www.programiz.com/csharp-programming/operator-precedence-associativity