Category Archives: .net

.Net Interview Questions

General Questions

Explain what a process is?

In general a process consists of or ‘owns’ the following:

  • A program image to execute, in machine code (think exe on disk)
  • Memory, typically some block of virtual memory
    • Executable code
    • Data (input / output
    • Call stack
    • Heap, to hold intermediate data

General CLR Questions

1. Explain garbage collection in .Net?

Garbage collection will occur under one of the following conditions:

  • The system is running low on physical memory
  • The heap surpasses an acceptable threshold. (This threshold is continuously adjusted as the process runs)
  • GC.Collect is called

The managed heap

There is a managed heap for each managed process, the heap is initialized by the garbage collector. The garbage collector calls win32 VirtualAlloc to reserve memory and VirtualFree to release memory.

The heap is comprised of the large object heap (objects greater than 85k, normally only arrays) and the small object heap

Generations

The heap is split into generations to manage long-lived and short-lived objects. Garbage collection generally occurs with the reclamation of short-lived objects which normally account for a small portion of the heap

Generation 0: Contains short-lived objects, i.e. temporary variables. Collection occurs most here
Generation 1: Contains short-lived objects, is a buffer between 0 & 2 generations
Generation 2: Contains long-lived objects, i.e. static instances, stateful instances

Types of garbage collection

Workstation mode

More suitable for long-running desktop applications, adds support for concurrent garbage collection which should mean that the application is more responsive during a collection.

Server mode

Best suited for asp.net, only supported on multi-processor machines

References

MSDN: Garbage Collection

2. What is boxing / unboxing?

Boxing occurs when a value type is passed to a method which expects an object or a value type is implicitly cast to an object.

ArrayList x = new ArrayList();
x.Add(10); // Boxing
int x =  10;
Object y = x; // Boxing

Unboxing is the reverse of this process, taking an object and casting it back to the value type.

int x = 10;

Object y = x; // Boxing

x = (int) y; // Unboxing

Problem?

Yes there is a performance cost when an item is boxed a new item must be created and allocated on the heap, 20x as long as a simple reference assignment. 4x penalty for unboxing.

Now with generics some use cases for boxing/unboxing go away. However in silverlight/WPF value convertors and dependency objects can cause lots of boxing to occur

3. What is a struct, when should you use one?

A struct is a value type and should be choosen instead of class if:

  • It logically represents a single value
  • Has an instance size smaller than 16 bytes
  • It is immutable
  • It will not be boxed frequently

4. What are weak references, why do you need them?

Enables you to take out a reference to an object without stopping the garbage collector from reclaiming that object.

Useful if you have very large objects, which are easy to recreate.

5. What is the dispose pattern?

The dispose pattern is used only for objects that access unmanaged resources. The garbage collector is very efficient in reclaiming memory of managed objects but has no knowledge of memory used by unmanaged native objects.

6. What is the difference between a Dictionary<TKey, TValue> and Hashtable?

Dictionary<TKey, TValue> Hashtable
Minimizes boxing/unboxing boxes value types: Add(object,object)
Needs synchronization Provides some sychronization via Hashtable.Synchronized(Hashtable) method
Newer >.net 2.0 Older Since 1.0
If key not found throws KeyNotFoundException If key not found returns null

Note that internally dictionary is implemented as a hashtable.

7. What is the cost of looking up an item in a Hashtable?

Retrieving the value of a dictionary or hashtable using it’s key is very fast close to O(1) in big-o notation. The speed of retrieval depends on the quality of the hashing algorithm of the type specified for TKey

Multi-threading Questions

1. How would you engineer a deadlock

  • Create two methods each acquiring a separate lock, that call each other say 5 times
  • Start two threads on separate methods
class Program
{
    private static int operations = 5;

    public static object lockA = new object();
    public static object lockB = new object();

    static void Main(string[] args)
    {
        Thread thread1 = new Thread(DoSomethingA);
        Thread thread2 = new Thread(DoSomethingB);

        thread1.Start();
        thread2.Start();

        thread1.Join();
        thread2.Join();
        Console.WriteLine(operations);
        Console.ReadKey();
    }

    public static void DoSomethingA()
    {
        lock (lockA)
        {
            Console.WriteLine("Lock DoSomething A " + Thread.CurrentThread.ManagedThreadId);
            if (operations > 0)
            {
                operations = operations - 1;
                Thread.Sleep(100);
                DoSomethingB();
            }
        }

        Console.WriteLine("Release DoSomething A " + Thread.CurrentThread.ManagedThreadId);
    }

    public static void DoSomethingB()
    {

        lock (lockB)
        {
            Console.WriteLine("Lock DoSomething B " + Thread.CurrentThread.ManagedThreadId);
            if (operations > 0)
            {
                operations = operations - 1;
                Thread.Sleep(100);
                DoSomethingA();                    
            }
        }

        Console.WriteLine("Release DoSomething B " + Thread.CurrentThread.ManagedThreadId);
    }
}

2. What are race conditions, how to stop them

Occur when more than one thread attempts to update shared data:

int x = 10;

…..

// Thread 1

x = x – 10;

// Thread 2

x = x + 1

To stop race conditions from happening you need to obtain exclusive locks, use semaphor, mutex, readwriterslim lock mechanism

3. What are some lock-less techniques for avoiding race conditions?

You can use volatile or Thread.MemoryBarrier() or the Interlocked class

4. What is does the keyword Volatile mean or do?

It ensures that the value of the field is always the most up-to-date value. Commonly used in multi-threaded applications that do not use locks to serialize access to shared data. When using a lock it causes the most up-to-date value to be retrieved.

Values can become stale when threads run on different processors asynchronously.

5. What is differenct between ManualResetEvents and AutoResetEvents?

When signaled via ‘Set’ threads waiting can all proceed until Reset() is called. With auto reset event only one waiting thread is unblocked when signalled ‘Set’ and the wait handle goes back to blocking other waiting threads until the next ‘Set’ message is sent.

Reactive Extensions (RX)

1. What are the IObservable<T> and IObserver<T> interfaces

IObservable<T> is a collection of things that can watched and defines a provider for push-based notification. And must implement a subscribe method.

IObserver<T> is essentially the listener to the collection and needs to implement OnNext, OnError, OnCompleted

Collections

1. What is the difference between IEnumerable<T> and IEnumerator<T>

IEnumerable<T> is a thing which can be enumerated over. Returns an IEnumerator

IEnumberator<T> is the thing that can do the enumeration, knows how to navigate the collection

Software design

1. List some design patterns

Creational patterns

Abstract factory

Provide an interface for creating families of related or dependent objects without specifying their concrete classes

http://en.wikipedia.org/wiki/Abstract_factory_pattern

Builder Pattern

Defines abstract interfaces and concrete classes for building complex objects

http://en.wikipedia.org/wiki/Builder_pattern

Singleton Pattern

Ensure a class only has one instance, and to provide a global point to access it.

Structural Patterns

Façade Pattern

A facade is an object that provides a simplified interface to a larger body of code

Pasted from <http://en.wikipedia.org/wiki/Facade_pattern>

Decorator

Attach additional responsibilities to an object dynamically keeping the same interface. Decorators provide a flexible alternative to subclassing for extending functionality.

Pasted from <http://en.wikipedia.org/wiki/Design_pattern_(computer_science)>

2. What is SOLID?

Initial

Stands for(acronym) Concept
S SRP
Single responsibility principle
an object should have only a single responsibility.
O OCP
Open/closed principle
“software entities … should be open for extension, but closed for modification”.
L LSP
Liskov substitution principle
“objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program”. See also design by contract.
I ISP
Interface segregation principle
“many client specific interfaces are better than one general purpose interface.”[5]
D DIP
Dependency inversion principle
one should “Depend upon Abstractions. Do not depend upon concretions.”[5]Dependency injection is one method of following this principle.
Advertisements
Tagged ,

What is the current state of REST frameworks in .Net 4.0

WCF WebHttp Services in .NET 4

Part of the official .Net 4.0 framework release.

WCF WebHttp Services is the flavor of WCF that is most appropriate for developers who need complete control over the URI, format, and protocol when building non-SOAP HTTP services— services that may or may not subscribe to RESTful architectural constraints.

Documentation

http://msdn.microsoft.com/en-us/library/bb412169.aspx

Example

Introducing WCF WebHttp Services in .NET 4: http://blogs.msdn.com/b/endpoint/archive/2010/01/06/introducing-wcf-webhttp-services-in-net-4.aspx

WCF WebApi

This project focuses on allowing developers to expose their apis for programmatic access over HTTP by browsers and devices.

Essentially this is a continuation of work done on the WCF Rest starter kit, and could be considered as a preview of wcf http services for .net 5.0?

WCF REST Starter Kit (depreciated)

The new WCF Web Api’s recently announced at PDC replace the REST Starter Kit and provide significant enhancements including better access to HTTP, more flexibility with representations and support for jQuery. Please go to http://wcf.codeplex.com/ for more information.

Source: http://aspnet.codeplex.com/wikipage?title=WCF%20REST&ProjectName=aspnet

Open Rasta

OpenRasta is a development framework targeting the Microsoft .NET platform for building web-based applications and services, and distributed under an Open-Source MIT License.

By focusing development around resources and HTTP methods, OpenRasta simplifies the creation of ReST-friendly interfaces.

Example

How to create a rest service using Open Rasta: http://blogs.7digital.com/dev/2011/02/02/rest-in-practice-and-openrasta/

RestSharp

http://restsharp.org/ A client only api for consuming rest services

RestSharp is a simple, open source REST client for .NET designed primarily for consuming third-party HTTP APIs. RestSharp is NOT:

  • A REST server framework
  • A SOAP client
Tagged , ,

How to add custom validators to the SharePoint ListFieldIterator

Requirements

Today I had the requirement to add custom validation logic to a SharePoint edit form. The edit form is being displayed using a ListFieldIterator. The requirement was to make sure the Date field could not be set to a date in the past.

The solution (Other solutions are available and are most probably better!) I came up with involved subclassing ListFieldIterator and attaching ASP.NET validators at run-time.

Challenge 1

How do you attach a ASP.NET validation control at run-time.

  • Attach the validator at the correct stage of the page/control life-cycle. In the case of the ListFieldIterator I wanted to attach it after the control had build it’s control tree. Override CreateChildControls, call base, then attach.
  • Find the FormField associated with the SharePoint field (SPField) you want to validate.I have an extension method that I use to parse the control hierarchy of a ListFieldIterator as follows:

Usage:

FormField formField = listFieldIterator.GetFormField("MyInternalFieldName");

public static class ListFieldIteratorExtensions
{
    public static FormField GetFormField(this ListFieldIterator listFieldIterator, string fieldName)
    {
        return GetFormField(listFieldIterator, GetFormFields(listFieldIterator), fieldName);
    }


    public static FormField GetFormField(this ListFieldIterator listFieldIterator, List<FormField> formFields, string fieldName)
    {
        FormField formField = (from form in formFields
                               where form.FieldName.Equals(fieldName, StringComparison.InvariantCultureIgnoreCase)
                               select form).FirstOrDefault();

        if (formField == null)
        {
            throw new GeneralApplicationException("Could not find form field: " + fieldName);
        }

        return formField;
    }

    public static List<FormField> GetFormFields(this ListFieldIterator listFieldIterator)
    {
        if (listFieldIterator == null)
        {
            return null;
        }

        return FindFieldFormControls(listFieldIterator);
    }        

    private static List<FormField> FindFieldFormControls(System.Web.UI.Control root)
    {
        List<FormField> baseFieldControls = new List<FormField>();

        foreach (System.Web.UI.Control control in root.Controls)
        {
            if (control is FormField && control.Visible)
            {
                FormField formField = control as FormField;
                if (formField.Field.FieldValueType == typeof(DateTime))
                {
                    HandleDateField(formField);
                }

                baseFieldControls.Add(formField);
            }
            else
            {
                baseFieldControls.AddRange(FindFieldFormControls(control));
            }
        }

        return baseFieldControls;
    }

    private static void HandleDateField(FormField formField)
    {
        if (formField.ControlMode == SPControlMode.Display)
        {
            return;
        }

        Control dateFieldControl = formField.Controls[0];
        if (dateFieldControl.Controls.Count > 0)
        {
            DateTimeControl dateTimeControl = (DateTimeControl) dateFieldControl.Controls[0].Controls[1];
            TextBox dateTimeTextBox = dateTimeControl.Controls[0] as TextBox;
            if (dateTimeTextBox != null)
            {
                if (!string.IsNullOrEmpty(dateTimeTextBox.Text))
                {
                    formField.Value = DateTime.Parse(dateTimeTextBox.Text, CultureInfo.CurrentCulture);
                }
            } 
        }
    }
}
  • Find the Control that is rendered by the FieldControl.Field.FieldRenderingControl. In my specific case a DateTimeField will render a DateTimeControl. Now that we have the form field we grab the rendering control:

Usage:

Control renderedControl = GetControl(formField);

private static Control GetControl(FieldMetadata formField)
{
    return formField.FindControlRecursive(x => x.GetType() == GetChildControlBasedOnFieldType(formField.Field.FieldRenderingControl));
}

private static Type GetChildControlBasedOnFieldType(object field)
{
    if (field is TextField)
    {
        return typeof(TextBox);
    }

    if (field is DropDownChoiceField)
    {
        return typeof(DropDownList);
    }

    if (field is DateTimeField)
    {
        return typeof (DateTimeControl);
    }

    return null;
}

public static Control FindControlRecursive(this Control control, Func<Control, bool> evaluate)
{
    if (evaluate.Invoke(control))
    {
        return control;
    }

    foreach (Control childControl in control.Controls)
    {
        Control foundControl = FindControlRecursive(childControl, evaluate);
        if (foundControl != null)
        {
            return foundControl;
        }
    }

    return null;
} 

  • Now we have found the control we want to validate, we can add the ASP.NET to it’s parent’s control collection

renderedControl.Parent.Controls.AddAfter(control, validator as Control);

Uses another little extension method:

public static void AddAfter(this ControlCollection collection, Control after, Control control)
{
    int indexFound = -1;
    int currentIndex = 0;
    foreach (Control controlToEvaluate in collection)
    {
        if (controlToEvaluate == after)
        {
            indexFound = currentIndex;
            break;
        }

        currentIndex = currentIndex + 1;
    }

    if (indexFound == -1)
    {
        throw new ArgumentOutOfRangeException("control", "Control not found");
    }

    collection.AddAt(indexFound + 1, control);
}

Tagged ,

How do you update the ‘Author’ or ‘Created by’ and ‘Editor’ or ‘Modified By / Last Modified’ fields of a list item (SPListItem)

Sometimes it’s useful to overwrite the created by and last modified by fields and get rid of that pesky ‘System Account’ !

Created By

The internal field name for the person who created a list item is ‘Author’ use SPBuiltInFieldId.Author to access this field. The display name for this field is ‘Created By’ it can be seen in the UI circled below:

SPListItem CreatedBy Author

Last modified

The internal field name for the person who created a list item is ‘Editor’ use SPBuiltInFieldId.Editor to access this field. The display name for this field is ‘Modified By’ it can be seen in the UI circled below:

SPListItem ModifiedBy Editor

Updating Created By, Modified By

The trick here is to call SPListItem.UpdateOverwriteVersion() instead of SPListItem.Update()

SPListItem item = list.Items[0];
item[SPBuiltInFieldId.Author] = "1;#Edward Wilde";
item[SPBuiltInFieldId.Editor] = "1;#Edward Wilde";
copiedItem.UpdateOverwriteVersion();
Tagged , ,

Cannot change the lookup list of the lookup field.

Ever get this error message

SPException “Cannot change the lookup list of the lookup field.”

Once a lookup field (SPFieldLookup) has had it’s LookupList and LookupWebId set you can’t change them.

There is a good reason for this if your lookup field is used in multiple lists or already has data entered, you would effectively break the referential integrity of the data. So what I’m showing here as a work-around to this error message should only be used if you are *sure* no lists reference the lookup column or no lists have any data using this column

Okay with the health warning out of the way the work-around is simply to update the Schema property to overwrite the intervalues for List & WebId

I created a handy extension method for dealing with the string manipulation:

Usage:

SPFieldLookup field = (SPFieldLookup)site.RootWeb.Fields[MyId];
field.UpdateLookupReferences(newWeb, newList);

Implementation:

public static class SPFieldLookupExtensions
{
    public static void UpdateLookupReferences(this SPFieldLookup lookupField, SPWeb web, SPList list)
    {
        if (string.IsNullOrEmpty(lookupField.LookupList))
        {
            lookupField.LookupWebId = web.ID;
            lookupField.LookupList = list.ID.ToString();
        }
        else
        {
            lookupField.SchemaXml =
                lookupField.SchemaXml
                    .ReplaceXmlAttributeValue("List", list.ID.ToString())
                    .ReplaceXmlAttributeValue("WebId", web.ID.ToString());
        }

        lookupField.Update(true);
    }
}

public static string ReplaceXmlAttributeValue(this string xml, string attributeName, string value)
{
    if (string.IsNullOrEmpty(xml))
    {
        throw new ArgumentNullException("xml");
    }

    if (string.IsNullOrEmpty(value))
    {
        throw new ArgumentNullException("value");
    }


    int indexOfAttributeName = xml.IndexOf(attributeName, StringComparison.CurrentCultureIgnoreCase);
    if (indexOfAttributeName == -1)
    {
        throw new ArgumentOutOfRangeException("attributeName", string.Format("Attribute {0} not found in source xml", attributeName));
    }

    int indexOfAttibuteValueBegin = xml.IndexOf('"', indexOfAttributeName);
    int indexOfAttributeValueEnd = xml.IndexOf('"', indexOfAttibuteValueBegin + 1);

    return xml.Substring(0, indexOfAttibuteValueBegin + 1) + value + xml.Substring(indexOfAttributeValueEnd);
}
Tagged ,

Programmatically determine is a feature is activated or even installed

Okay so ever needed to see if a particular web or site feature is activated? Well if it’s activated it will be in the SPWeb.Features SPFeatureCollection or SPSite.Features. If it’s not activated it won’t be. Simple.

To check if a feature is installed examine the feature definitions collection on the SPFarm object, below are a couple of little extension methods that demonstrate this concept.

/// <summary>
/// Defines extensions made to the <see cref="SPWeb"/> class
/// </summary>
[CLSCompliant(false)]
public static class SPWebExtensions
{
    public static bool IsFeatureActivated(this SPWeb web, Guid featureId)
    {
        return web.Features[featureId] != null;
    }

    public static bool IsFeatureInstalled(this SPWeb web, Guid featureId)
    {
        SPFeatureDefinition featureDefinition = SPFarm.Local.FeatureDefinitions[featureId];
        if (featureDefinition == null)
        {
            return false;
        }

        if (featureDefinition.Scope != SPFeatureScope.Web)
        {
            throw new GeneralApplicationException(
                string.Format("Feature with the ID {0} was installed but is not scoped at the web level.", featureId));
        }

        return true;
    }
}
Tagged , , ,

Lookup the Netbios name of a domain using directory services

Okay so its pretty easy to get the fully qualified domain name (FQDN).

using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;

Console.WriteLine(Domain.GetCurrentDomain().Name)

But what happens if you want to get the old-skool netbios name. The quickest way is to use System.Environment:

using System

Console.WriteLine(System.Environment.UserDomainName)

This gets the network domain name associated with the current user. So not much good if your code is running as a service that could well be configured to run at Network Account. Surely you can do this using DirectoryServices? Bit of Googling and coding and we have a nice little extension method which does just that

/// <summary>
    /// Defines extentions made to the <see cref="Domain"/> class.
    /// </summary>
    public static class DomainExtensions
    {
        public static string GetNetbiosName(this Domain domain)
        {

            // Bind to RootDSE and grab the configuration naming context
            DirectoryEntry rootDSE = new DirectoryEntry(@"LDAP://RootDSE");
            DirectoryEntry partitions = new DirectoryEntry(@"LDAP://cn=Partitions," + rootDSE.Properties["configurationNamingContext"].Value);

            DirectoryEntry domainEntry = domain.GetDirectoryEntry();

            //Iterate through the cross references collection in the Partitions container
            DirectorySearcher directorySearcher = new DirectorySearcher(partitions)
               {
                    Filter = "(&(objectCategory=crossRef)(ncName=" +
                         domainEntry.Path
                             .Replace("LDAP://", string.Empty)
                             .Replace(domain.Name + "/", string.Empty) + "))",
                    SearchScope = SearchScope.Subtree
               };

            directorySearcher.PropertiesToLoad.Add("nETBIOSName");

            //Display result (should only be one)
            SearchResultCollection results = directorySearcher.FindAll();
            if (results.Count == 0)
            {
                return null;
            }

            return results[0].Properties["nETBIOSName"][0].ToString();
        }
    }

Usage:

Domain.GetCurrentDomain().GetNetbiosName()

Note You can also retrieve the netbios entry using netapi32.dll http://blog.dotsmart.net/2009/03/11/getting-a-machine%E2%80%99s-netbios-domain-name-in-csharp

Tagged , , ,

How to serialize List using XML serialization

Okay so this one is filed under the “I keep looking up the same things” category. In .Net 1 lists of objects were commonly serialized either using an Array or an ArrayList property:

....
/// <summary>
/// List Item permissions to be given to this group
/// </summary>
[XmlArray("ListItems"), XmlArrayItem("ListItemPermissions", typeof(ListItemPermissions))]
public ArrayList ListItems
{
        get { return _listItems; }
        set { _listItems = value; }
}
....
or
....
public Group[] Groups
{
        get { return this.groups; }
        set { this.groups = value; }
}

In .net 2.0 List<T> can be serialized by adding the XmlArray attribute in the property declaration, as follows:

[XmlArray("Audiences")]
public List<PortalAudience> Audiences { get; set; }

…..

Tagged , ,

My SVN Global Ignore Pattern for C# and Resharper

*\bin* *\obj* *.suo *.user *.bak **.ReSharper** **\_ReSharper.** StyleCop.Cache

Tagged , , ,

XslCompiledTransform !♥ the UTF-8 BOM : System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1.

Recently I came across a rather annoying issue with the XslCompiledTransform class. Namely it really doesn’t like having a BOM (byte order mark) shoved down it’s load method.

I got a the follow error message and stack trace

System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
at System.Xml.XmlTextReaderImpl.ParseRootLevelWhitespace()
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.Xsl.Xslt.XsltInput.ReadNextSiblingHelper()
at System.Xml.Xsl.Xslt.XsltInput.ReadNextSibling()
at System.Xml.Xsl.Xslt.XsltInput.MoveToNextSibling()
at System.Xml.Xsl.Xslt.XsltInput.Start()
at System.Xml.Xsl.Xslt.XsltLoader.LoadDocument()
at System.Xml.Xsl.Xslt.XsltLoader.LoadStylesheet(XmlReader reader, Boolean include)
System.Xml.Xsl.XslLoadException: XSLT compile error.
at System.Xml.Xsl.Xslt.XsltLoader.LoadStylesheet(XmlReader reader, Boolean include)
at System.Xml.Xsl.Xslt.XsltLoader.Load(Compiler compiler, Object stylesheet, XmlResolver xmlResolver)
at System.Xml.Xsl.Xslt.Compiler.Compile(Object stylesheet, XmlResolver xmlResolver, ref QilExpression qil)
at System.Xml.Xsl.XslCompiledTransform.CompileXsltToQil(Object stylesheet, XsltSettings settings, XmlResolver stylesheetResolver)
at System.Xml.Xsl.XslCompiledTransform.LoadInternal(Object stylesheet, XsltSettings settings, XmlResolver stylesheetResolver)
at System.Xml.Xsl.XslCompiledTransform.Load(XmlReader stylesheet)

Viewing the input data to the XslCompiledTransform in debug mode showed a perfectly valid and lovely XSLT file. Visual studio does not display the BOM in the visual representation of the string. Saving the string to disk and examining it in a hex editor revealed that the first 3 bytes were indeed the BOM for UTF-8: EF BB BF

I wrote a little extension method for the bytes class to get rid of the BOM if it’s present

///

/// Removes the byte order mark.
///

/// The bytes. /// byte array without the BOM.
public static byte[] RemoveByteOrderMark(this byte[] bytes)
{
if (!bytes.StartsWithByteOrderMark())
{
return bytes;
}

byte[] results = new byte[bytes.Length – 3];
Array.Copy(bytes, 3, results, 0, bytes.Length – 3);

return results;
}

///

/// Determines if the byte array starts with a byte order mark.
///

/// The bytes. /// true if the byte array starts with a byte order mark; otherwise false.
public static bool StartsWithByteOrderMark(this byte[] bytes)
{
if (bytes == null)
{
return false;
}

if (bytes.Length < 3) { return false; } return bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF; } [/sourcecode]

Tagged