C# is a general-purpose and object-oriented programming language developed by Microsoft. It is mostly used for developing desktop and web applications. So, today we will be talking about the 11 frequently asked questions about C# programming language.
11 Frequently Asked C# Questions
1. What is the difference between String and string in C#?
Answer:
string
is an alias in C# for System.String
.
So technically, there is no difference. It’s like int vs. System.Int32.
As far as guidelines, it’s generally recommended to use string any time you’re referring to an object.
e.g.
string place = "world";
Likewise, it’s generally recommended to use String
if you need to refer specifically to the class.
e.g.
string greet = String.Format("Hello {0}!", place);
This is the style that Microsoft tends to use in their examples.
It appears that the guidance in this area may have changed, as StyleCop now enforces the use of the C# specific aliases.
Alternative Answer:
string
is an alias for System.String
. They compile to the same code, so at execution time there is no difference whatsoever. This is just one of the aliases in C#. The complete list is:
object: System.Object
string: System.String
bool: System.Boolean
byte: System.Byte
sbyte: System.SByte
short: System.Int16
ushort: System.UInt16
int: System.Int32
uint: System.UInt32
long: System.Int64
ulong: System.UInt64
float: System.Single
double: System.Double
decimal: System.Decimal
char: System.Char
Apart from string
and object
, the aliases are all to value types. decimal
is a value type, but not a primitive type in the CLR. The only primitive type which doesn’t have an alias is System.IntPtr
.
In the spec, the value type aliases are known as “simple types”. Literals can be used for constant values of every simple type; no other value types have literal forms available. (Compare this with VB, which allows DateTime
literals, and has an alias for it too.)
There is one circumstance in which you have to use the aliases: when explicitly specifying an enum’s underlying type. For instance:
public enum Foo : UInt32 {} // Invalid
public enum Bar : uint {} // Valid
That’s just a matter of the way the spec defines enum declarations – the part after the colon has to be the integral-type production, which is one token of sbyte
, byte
, short
, ushort
, int
, uint
, long
, ulong
, char…
as opposed to a type production as used by variable declarations for example. It doesn’t indicate any other difference.
Finally, when it comes to which to use: the CLR type is for any APIs. It really doesn’t matter too much which you use in terms of implementation – consistency among your team is nice, but no-one else is going to care. On the other hand, it’s genuinely important that if you refer to a type in an API, you do so in a language-neutral way. A method called ReadInt32
is unambiguous, whereas a method called ReadInt
requires interpretation. The caller could be using a language that defines an int
alias for Int16
, for example. The .NET framework designers have followed this pattern, good examples being in the BitConverter
, BinaryReader
, and Convert
classes.
2. How to cast an int to enum?
Answer:
From a string:
YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString);
// The foo.ToString().Contains(",") check is necessary for enumerations marked with an [Flags] attribute
if (!Enum.IsDefined(typeof(YourEnum), foo) && !foo.ToString().Contains(","))
{
throw new InvalidOperationException($"{yourString} is not an underlying value of the YourEnum enumeration.")
}
From an int:
YourEnum foo = (YourEnum)yourInt;
From the number also you can
YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);
Alternative Answer:
Just cast it:
MyEnum e = (MyEnum)3;
You can check if it’s in range using Enum.IsDefined:
if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }
3. What is the best way to iterate over a dictionary?
Answer:
The best way to do is
foreach(KeyValuePair<string, string> entry in myDictionary)
{
// do something with entry.Value or entry.Key
}
Alternative Answer:
If you are trying to use a generic Dictionary in C# like you would use an associative array in another language:
foreach(var item in myDictionary)
{
foo(item.Key);
bar(item.Value);
}
Or, if you only need to iterate over the collection of keys, use
foreach(var item in myDictionary.Keys)
{
foo(item);
}
And lastly, if you’re only interested in the values:
foreach(var item in myDictionary.Values)
{
foo(item);
}
(Take note that the var
keyword is an optional C# 3.0 and above feature, you could also use the exact type of your keys/values here)
4. What are the correct version numbers for C#?
Answer:
C# language version history:
These are the versions of C# known about at the time of this writing:
- C# 1.0 released with .NET 1.0 and VS2002 (January 2002)
-
C# 1.2 (bizarrely enough); released with .NET 1.1 and VS2003 (April 2003). First version to call
Dispose
onIEnumerators
which implementedIDisposable
. A few other small features. - C# 2.0 released with .NET 2.0 and VS2005 (November 2005). Major new features: generics, anonymous methods, nullable types, iterator blocks
-
C# 3.0 released with .NET 3.5 and VS2008 (November 2007). Major new features: lambda expressions, extension methods, expression trees, anonymous types, implicit typing (
var
), query expressions -
C# 4.0 released with .NET 4 and VS2010 (April 2010). Major new features: late binding (
dynamic
), delegate and interface generic variance, more COM support, named arguments, tuple data type, and optional parameters - C# 5.0 released with .NET 4.5 and VS2012 (August 2012). Major features: async programming, caller info attributes. Breaking change: loop variable closure.
-
C# 6.0 released with .NET 4.6 and VS2015 (July 2015). Implemented by Roslyn. Features: initializers for automatically implemented properties, using directives to import static members, exception filters, element initializers,
await
incatch
andfinally
, extensionAdd
methods in collection initializers. -
C# 7.0 released with .NET 4.7 and VS2017 (March 2017) Major new features: tuples, ref locals and ref return, pattern matching (including pattern-based switch statements), inline
out
parameter declarations, local functions, binary literals, digit separators, and arbitrary async returns. - C# 7.1 released with VS2017 v15.3 (August 2017) New features: async main, tuple member name inference, default expression, pattern matching with generics.
- C# 7.2 released with VS2017 v15.5 (November 2017) New features: private protected access modifier, Span, aka interior pointer, aka stack only struct, everything else.
-
C# 7.3 released with VS2017 v15.7 (May 2018). New features: enum, delegate and
unmanaged
generic type constraints.ref
reassignment. Unsafe improvements:stackalloc
initialization, unpinned indexedfixed
buffers, customfixed
statements. Improved overloading resolution. Expression variables in initializers and queries.==
and!=
defined for tuples. Auto-properties’ backing fields can now be targeted by attributes. - C# 8.0 released with .Net Core 3.0 and VS2019 v16.3 (September 2019). Major new features: nullable reference-types, Asynchronous streams, Indices and Ranges, Readonly members, using declarations, default interface methods, Static local functions, and Enhancement of interpolated verbatim strings.
5. How to clone or deep copy an object so that the cloned object can be modified without any changes being reflected in the original object?
Answer:
Whilst the standard practice is to implement the ICloneable
interface, here’s a nice deep clone object copier found on The Code Project and incorporated it.
As mentioned, it does require your objects to be serializable.
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
/// <summary>
/// Reference Article http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
/// Provides a method for performing a deep copy of an object.
/// Binary Serialization is used to perform the copy.
/// </summary>
public static class ObjectCopier
{
/// <summary>
/// Perform a deep Copy of the object.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
public static T Clone<T>(T source)
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", nameof(source));
}
// Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null))
{
return default(T);
}
IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream();
using (stream)
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
}
The idea is that it serializes your object and then deserializes it into a fresh object. The benefit is that you don’t have to concern yourself about cloning everything when an object gets too complex.
And with the use of extension methods (also from the originally referenced source):
In case you prefer to use the new extension methods of C# 3.0, change the method to have the following signature:
public static T Clone<T>(this T source)
{
//...
}
Now the method call simply becomes objectBeingCloned.Clone();
.
You can also use JSON to do this, it should be lighter, and avoids the overhead of [Serializable] tags.
/// <summary>
/// Perform a deep Copy of the object, using Json as a serialisation method. NOTE: Private members are not cloned using this method.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
public static T CloneJson<T>(this T source)
{
// Don't serialize a null object, simply return the default for that object
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);
}
Alternative Answer:
If your object is out of the box JSON serializable then this method will do the trick. This requires no modification or implementation of interfaces on the cloned class, just a JSON serializer like JSON.NET.
public static T Clone<T>(T source)
{
var serialized = JsonConvert.SerializeObject(source);
return JsonConvert.DeserializeObject<T>(serialized);
}
Also, you can use this extension method
public static class SystemExtension
{
public static T Clone<T>(this T source)
{
var serialized = JsonConvert.SerializeObject(source);
return JsonConvert.DeserializeObject<T>(serialized);
}
}
6. How to get a consistent byte representation of strings in C# without manually specifying an encoding?
Answer:
You can just do this:
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
// Do NOT use on arbitrary bytes; only use on GetBytes's output on the SAME system
static string GetString(byte[] bytes)
{
char[] chars = new char[bytes.Length / sizeof(char)];
System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
return new string(chars);
}
Alternative Answer:
It also depends on the encoding of your string (ASCII, UTF-8, …).
For example:
byte[] b1 = System.Text.Encoding.UTF8.GetBytes (myString);
byte[] b2 = System.Text.Encoding.ASCII.GetBytes (myString);
A small sample of why encoding matters:
string pi = "\u03a0";
byte[] ascii = System.Text.Encoding.ASCII.GetBytes (pi);
byte[] utf8 = System.Text.Encoding.UTF8.GetBytes (pi);
Console.WriteLine (ascii.Length); //Will print 1
Console.WriteLine (utf8.Length); //Will print 2
Console.WriteLine (System.Text.Encoding.ASCII.GetString (ascii)); //Will print '?'
ASCII simply isn’t equipped to deal with special characters.
Internally, the .NET framework uses UTF-16 to represent strings, so if you simply want to get the exact bytes that .NET uses, use System.Text.Encoding.Unicode.GetBytes (...)
.
See Character Encoding in the .NET Framework (MSDN) for more information.
7. Should ‘using’ directives be inside or outside the namespace?
Answer:
There is actually a (subtle) difference between the two. Imagine you have the following code in File1.cs:
// File1.cs
using System;
namespace Outer.Inner
{
class Foo
{
static void Bar()
{
double d = Math.PI;
}
}
}
Now imagine that someone adds another file (File2.cs) to the project that looks like this:
// File2.cs
namespace Outer
{
class Math
{
}
}
The compiler searches Outer
before looking at those using
directives outside the namespace, so it finds Outer.Math
instead of System.Math
. Unfortunately (or perhaps fortunately?), Outer.Math
has no PI
member, so File1 is now broken.
This changes if you put the using
inside your namespace declaration, as follows:
// File1b.cs
namespace Outer.Inner
{
using System;
class Foo
{
static void Bar()
{
double d = Math.PI;
}
}
}
Now the compiler searches System
before searching Outer
, finds System.Math
, and all is well.
Some would argue that Math
might be a bad name for a user-defined class since there’s already one in System
; the point here is just that there is a difference, and it affects the maintainability of your code.
It’s also interesting to note what happens if Foo
is in the namespace Outer
, rather than Outer.Inner
. In that case, adding Outer.Math
in File2 breaks File1 regardless of where the using
goes. This implies that the compiler searches the innermost enclosing namespace before it looks at any using
directive.
8. How to generate a random int number?
Answer:
The Random
class is used to create random numbers. (Pseudo-random that is of course.).
Example:
Random rnd = new Random();
int month = rnd.Next(1, 13); // creates a number between 1 and 12
int dice = rnd.Next(1, 7); // creates a number between 1 and 6
int card = rnd.Next(52); // creates a number between 0 and 51
If you are going to create more than one random number, you should keep the Random
instance and reuse it. If you create new instances too close in time, they will produce the same series of random numbers as the random generator is seeded from the system clock.
Alternative Answer:
Every time you do new Random() it is initialized . This means that in a tight loop you get the same value lots of times. You should keep a single Random instance and keep using Next on the same instance.
//Function to get random number
private static readonly Random getrandom = new Random();
public static int GetRandomNumber(int min, int max)
{
lock(getrandom) // synchronize
{
return getrandom.Next(min, max);
}
}
9. How to create an Excel (.XLS and .XLSX) file in C# without installing Microsoft Office?
Answer:
You can use a library called ExcelLibrary. It’s a free, open-source library posted on Google Code: ExcelLibrary
It will not write to the new .xlsx format yet, but they are working on adding that functionality in.
It’s very simple, small, and easy to use. Plus it has a DataSetHelper that lets you use DataSets and DataTables to easily work with Excel data.
ExcelLibrary seems to still only work for the older Excel format (.xls files), but maybe adding support in the future for newer 2007/2010 formats.
You can also use EPPlus, which works only for Excel 2007/2010 format files (.xlsx files). There’s also NPOI which works with both.
There are a few known bugs with each library. In all, EPPlus seems to be the best choice as time goes on. It seems to be more actively updated and documented as well.
Also, EPPlus has support for Pivot Tables and ExcelLibrary may have some support (Pivot table issue in ExcelLibrary)
Here are a couple of links for quick reference:
ExcelLibrary – GNU Lesser GPL
EPPlus – GNU Lesser General Public License (LGPL)
NPOI – Apache License
Here some example code for ExcelLibrary:
Here is an example of taking data from a database and creating a workbook from it. Note that the ExcelLibrary code is the single line at the bottom:
//Create the data set and table
DataSet ds = new DataSet("New_DataSet");
DataTable dt = new DataTable("New_DataTable");
//Set the locale for each
ds.Locale = System.Threading.Thread.CurrentThread.CurrentCulture;
dt.Locale = System.Threading.Thread.CurrentThread.CurrentCulture;
//Open a DB connection (in this example with OleDB)
OleDbConnection con = new OleDbConnection(dbConnectionString);
con.Open();
//Create a query and fill the data table with the data from the DB
string sql = "SELECT Whatever FROM MyDBTable;";
OleDbCommand cmd = new OleDbCommand(sql, con);
OleDbDataAdapter adptr = new OleDbDataAdapter();
adptr.SelectCommand = cmd;
adptr.Fill(dt);
con.Close();
//Add the table to the data set
ds.Tables.Add(dt);
//Here's the easy part. Create the Excel worksheet from the data set
ExcelLibrary.DataSetHelper.CreateWorkbook("MyExcelFile.xls", ds);
Creating the Excel file is as easy as that. You can also manually create Excel files.
10. What is the best way to give a C# auto-property an initial value?
Answer:
In C# 5 and earlier, to give auto-implemented properties an initial value, you have to do it in a constructor.
Since C# 6.0, you can specify the initial value in-line. The syntax is:
public int X { get; set; } = x; // C# 6 or higher
DefaultValueAttributeis
intended to be used by the VS designer (or any other consumer) to specify a default value, not an initial value. (Even if in the designed object, the initial value is the default value).
At compile time DefaultValueAttribute
will not impact the generated IL and it will not be read to initialize the property to that value.
Example of attributes that impact the IL are ThreadStaticAttribute
, CallerMemberNameAttribute
, …
Alternative Answer:
C# 6 :
With C# 6 you can initialize auto-properties directly.
C# 5 and below:
Though the intended use of the attribute is not to actually set the values of the properties, you can use reflection to always set them anyway.
public class DefaultValuesTest
{
public DefaultValuesTest()
{
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(this))
{
DefaultValueAttribute myAttribute = (DefaultValueAttribute)property.Attributes[typeof(DefaultValueAttribute)];
if (myAttribute != null)
{
property.SetValue(this, myAttribute.Value);
}
}
}
public void DoTest()
{
var db = DefaultValueBool;
var ds = DefaultValueString;
var di = DefaultValueInt;
}
[System.ComponentModel.DefaultValue(true)]
public bool DefaultValueBool { get; set; }
[System.ComponentModel.DefaultValue("Good")]
public string DefaultValueString { get; set; }
[System.ComponentModel.DefaultValue(27)]
public int DefaultValueInt { get; set; }
}
11. How to Sort a List by a property in the object?
Answer:
The easiest way is to use Linq:
List<Order> SortedList = objListOrder.OrderBy(o=>o.OrderDate).ToList();
Alternative Answer:
If you need to sort the list in-place then you can use the Sort
method, passing a Comparison<T>
delegate:
objListOrder.Sort((x, y) => x.OrderDate.CompareTo(y.OrderDate));
If you prefer to create a new, sorted sequence rather than sort in-place then you can use LINQ’s OrderBy
method.
In Conclusion
These are the 11 most asked C# questions. If you have any suggestions or any confusion, please comment below. If you need any help, we will be glad to help you.
We, at Truemark, provide services like web and mobile app development, digital marketing, and website development. So, if you need any help and want to work with us, please feel free to contact us.
Hope this article helped you.
This article was first published on DevPost.
Top comments (0)