Best .net-4.0 questions in July 2011

29 votes

I am trying to do operator overloads for "+=", but I can't. I can only make an operator overload for "+".

How come?

Edit

The reason this is not working is that I have a Vector class (with an X and Y field). Consider the following example.

vector1 += vector2;

If my operator overload is set to:

public static Vector operator +(Vector left, Vector right)
{
    return new Vector(right.x + left.x, right.y + left.y);
}

Then the result won't be added to vector1, but instead, vector1 will become a brand new Vector by reference as well.

Updated the answer, see below.


Overloadable Operators, from MSDN:

Assignment operators cannot be overloaded, but +=, for example, is evaluated using +, which can be overloaded.

Even more, none of assignment operator can't be overloaded. I think, this is because there will be a some effect for the Garbage collection and memory management, which is potential security hole in CLR strong typed world.

Nevertheless, let see what exactly operator is. According to the famous Jeffrey Richter's book, each programming language has its own operators list, which are compiled in a special method calls, and CLR itself doesn't know anything about operators. So let's see what exactly stays behind the + and += operators.

See this simple code:

    Decimal d = 10M;
    d = d + 10M;
    Console.WriteLine(d);

Let view the IL-code for this instructions:

  IL_0000:  nop
  IL_0001:  ldc.i4.s   10
  IL_0003:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32)
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  ldc.i4.s   10
  IL_000c:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32)
  IL_0011:  call       valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Addition(valuetype [mscorlib]System.Decimal,
                                                                                                valuetype [mscorlib]System.Decimal)
  IL_0016:  stloc.0

Now lets see this code:

Decimal d1 = 10M;
d1 += 10M;
Console.WriteLine(d1);

And IL-code for this:

  IL_0000:  nop
  IL_0001:  ldc.i4.s   10
  IL_0003:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32)
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  ldc.i4.s   10
  IL_000c:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32)
  IL_0011:  call       valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Addition(valuetype [mscorlib]System.Decimal,
                                                                                                valuetype [mscorlib]System.Decimal)
  IL_0016:  stloc.0

They are equal! So the += operator is just a sugar for your program in C#, and you can simply overload + operator.

For example:

    class Foo
    {
        private int c1;

        public Foo(int c11)
        {
            c1 = c11;
        }

        public static Foo operator +(Foo c1, Foo x)
        {
            return new Foo(c1.c1 + x.c1);
        }
    }

    static void Main(string[] args)
    {
        Foo d1 =  new Foo (10);
        Foo d2 = new Foo(11);
        d2 += d1;
    }

This code will be compiled and successfully run as:

  IL_0000:  nop
  IL_0001:  ldc.i4.s   10
  IL_0003:  newobj     instance void ConsoleApplication2.Program/Foo::.ctor(int32)
  IL_0008:  stloc.0
  IL_0009:  ldc.i4.s   11
  IL_000b:  newobj     instance void ConsoleApplication2.Program/Foo::.ctor(int32)
  IL_0010:  stloc.1
  IL_0011:  ldloc.1
  IL_0012:  ldloc.0
  IL_0013:  call       class ConsoleApplication2.Program/Foo ConsoleApplication2.Program/Foo::op_Addition(class ConsoleApplication2.Program/Foo,
                                                                                                          class ConsoleApplication2.Program/Foo)
  IL_0018:  stloc.1

Update:

According to your Update - as the @Eric Lippert says, you really should have the vectors as immutable objects. Result of adding of the two vectors is a new vector, not the first one with different sizes.

If, for some reason you need to change first vector, you can use this overload (but as for me, this is very strange behaviour):

public static Vector operator +(Vector left, Vector right)
{
    left.x += right.x;
    left.y += right.y;
    return left;
}

Enum addition vs subtraction and casting

19 votes

Why does addition require a cast but subtraction works without a cast? See the code below to understand what I am asking

public enum Stuff
{
    A = 1,
    B = 2,
    C = 3
}

var resultSub = Stuff.A - Stuff.B; // Compiles
var resultAdd = Stuff.A + Stuff.B; // Does not compile
var resultAdd2 = (int)Stuff.A + Stuff.B; // Compiles     

note: For both addition and subtraction it does not matter whether result is out of range (of the enum) or not in all three examples above.

Good question - I was surprised that the first and third lines worked.

However, they are supported in the C# language specification - in section 7.8.4, it talks about enumeration addition:

Every enumeration type implicitly provides the following pre-defined operators, where E is the enum type and U is the underlying type of E:

E operator +(E x, U y)
E operator +(U x, E y)

At runtime, these operators are ealuated exactly as (E)((U)x + (U)y)

And in section 7.8.5:

Every enumeration type implicitly provides the following predefined operator, where E is the enum type and U is the underlying type of E:

U operator -(E x, E y)

This operator is evaluated exactly as (U)((U)x - (U)y)). In other words, the operator computes the difference between the ordinal values of x and y, and the type of the result is the underlying type of the enumeration.

E operator -(E x, U y);

This operator is evaluated exactly as (E)((U)x - y). In other words, the operator subtracts a value from the underlying type of the enumeration, yielding a value of the enumeration.

So that's why the compiler behaves like that - because it's what the C# spec says to do :)

I wasn't aware that any of these operators exist, and I've never knowingly seen them used. I suspect the reasons for their existence are buried somewhere in the language design meeting notes that Eric Lippert occasionally dives into - but I also wouldn't be surprised if they were regretted as adding features for little benefit. Then again, maybe they're really useful in some situations :)

Is it possible to create routes dynamically in .NET 4?

9 votes

In our application we use the new .NET 4 routing system to route certain requests to other parts of the site. We are only allowed to publish our site code in late evenings which means we have to stay late at work to publish any code changes. We frequently have the need to create custom routes to support legacy links to old content and route them to the new content. These are often needed right away and as our routes are defined in compiled global.asax we reach an impasse when we need these live immediately but cannot do a code push.

Is there a way that we could define routes in some sort of configuration file and have the site read them in programmatically without restarting the application?

Phil Haack gives a solution for dynamically registering routes here: http://haacked.com/archive/2010/01/17/editable-routes.aspx

I think that covers what you want, including not having the whole Web App restart.

WPF MVVM implementing the viewmodel to reflect the base model?

5 votes

Something that has been confusing me for a while now with WPF MVVM is for example, when I have a base model containing nothing but a few properties and some validation code and I then build a view model around this base model, how should the view model be structured.

For Example:

Base Model ->

Imports ModellingHelper
Imports FTNHelper
Imports System.ComponentModel
Imports System.ComponentModel.DataAnnotations

Public Class Parser
    Inherits BaseModel

    <Required(ErrorMessage:="Name is required.")>
    Public Property Name As String
        Get
            Return GetValue(Function() Name)
        End Get
        Set(value As String)
            SetValue(Function() Name, value)
        End Set
    End Property

    <Required(ErrorMessage:="Description is required.")>
    Public Property Description As String
        Get
            Return GetValue(Function() Description)
        End Get
        Set(value As String)
            SetValue(Function() Description, value)
        End Set
    End Property

    Public Property InputHeaderInfo As InputHeader
        Get
            Return GetValue(Function() InputHeaderInfo)
        End Get
        Set(value As InputHeader)
            SetValue(Function() InputHeaderInfo, value)
        End Set
    End Property

    Public Property InputVariables As ObservableList(Of Variable)
        Get
            Return GetValue(Function() InputVariables)
        End Get
        Set(value As ObservableList(Of Variable))
            SetValue(Function() InputVariables, value)
        End Set
    End Property

    Public Property OutputVariables As ObservableList(Of Variable)
        Get
            Return GetValue(Function() OutputVariables)
        End Get
        Set(value As ObservableList(Of Variable))
            SetValue(Function() OutputVariables, value)
        End Set
    End Property

    Public Sub New()
        Name = "New Parser"
        Description = "This is a new parser."
        InputHeaderInfo = New InputHeader()
        InputVariables = New ObservableList(Of Variable)
        OutputVariables = New ObservableList(Of Variable)
    End Sub
End Class

ViewModel ->

Imports WinTransform.DataModel
Imports System.IO
Imports WPFHelper
Imports System.ComponentModel
Imports System.ComponentModel.DataAnnotations
Imports ModellingHelper
Imports Omu.ValueInjecter

Namespace ViewModels
    Public Class ParserViewModel
        Inherits ViewBase

#Region "Properties"
        Public Property Source As Parser
            Get
                Return GetValue(Function() Source)
            End Get
            Set(value As Parser)
                SetValue(Function() Source, value)
            End Set
        End Property

        Public Property InputFile As FileInfo
            Get
                Return GetValue(Function() InputFile)
            End Get
            Set(value As FileInfo)
                SetValue(Function() InputFile, value)
                NotifyPropertyChanged(Function() InputFileContents)
                NotifyPropertyChanged(Function() InputFileParseLine)
                NotifyPropertyChanged(Function() TabVisability)
            End Set
        End Property

        Public ReadOnly Property InputFileContents As String
            Get
                If Not InputFile Is Nothing Then
                    Dim mReader = InputFile.OpenText()
                    Try
                        Return mReader.ReadToEnd()
                    Catch ex As Exception
                        MessageBox.Show(String.Format("Failed to load transform file contents: {0}", ex.Message))
                    Finally
                        mReader.Close()
                    End Try
                End If
                Return String.Empty
            End Get
        End Property

        Public ReadOnly Property InputFileParseLine As String
            Get
                If Not InputFile Is Nothing Then
                    Dim mReader = InputFile.OpenText()
                    Try
                        Dim mLines = mReader.ReadToEnd().Split(vbNewLine).Select(Function(l As String) l.Trim())
                        Dim mLineNo = Source.InputHeaderInfo.TitleLinesFixed + Source.InputHeaderInfo.TitleLinesSkipped + Source.InputHeaderInfo.ColumnHeaderLines + Source.InputHeaderInfo.LinesFixed + Source.InputHeaderInfo.LinesSkipped
                        If mLineNo >= 0 And mLineNo < mLines.Count() Then
                            Return mLines(mLineNo)
                        End If
                    Catch ex As Exception
                        MessageBox.Show(String.Format("Failed to load transform file contents: {0}", ex.Message))
                    Finally
                        mReader.Close()
                    End Try
                End If
                Return String.Empty
            End Get
        End Property

        Public ReadOnly Property TabVisability As Visibility
            Get
                If Not InputFile Is Nothing Then
                    Return Visibility.Visible
                End If
                Return Visibility.Hidden
            End Get
        End Property

        Public ReadOnly Property InputVariablesViews As ObservableList(Of VariableViewModel)
            Get
                Dim mVars As New ObservableList(Of VariableViewModel)
                For Each mVar In Source.InputVariables
                    mVars.Add(New VariableViewModel(mVar))
                Next
                AddHandler mVars.CollectionChanged, Sub() Source.InputVariables.RefreshList(mVars.Select(Function(v As VariableViewModel) v.Source))
                Return mVars
            End Get
        End Property

        Public ReadOnly Property OutputVariablesViews As ObservableList(Of VariableViewModel)
            Get
                Dim mVars As New ObservableList(Of VariableViewModel)
                For Each mVar In Source.OutputVariables
                    mVars.Add(New VariableViewModel(mVar))
                Next
                AddHandler mVars.CollectionChanged, Sub() Source.OutputVariables.RefreshList(mVars.Select(Function(v As VariableViewModel) v.Source))
                Return mVars
            End Get
        End Property

        Public Property IsSaved As Boolean
            Get
                If String.IsNullOrEmpty(SaveFile) Then
                    Return False
                End If

                If Not IsValid Then
                    Return False
                End If

                Return GetValue(Function() IsSaved)
            End Get
            Set(value As Boolean)
                SetValue(Function() IsSaved, value)
            End Set
        End Property

        Public Property SaveFile As String
            Get
                Return GetValue(Function() SaveFile)
            End Get
            Set(value As String)
                SetValue(Function() SaveFile, value)
            End Set
        End Property
#End Region

#Region "Commands"
        Public ReadOnly Property SelectInputFile As ICommand
            Get
                Return New RelayCommand(Sub() SelectInputFileExecute())
            End Get
        End Property

        Private Sub SelectInputFileExecute()
            Dim mOpenDialog = OpenDialog
            If mOpenDialog.ShowDialog() Then
                InputFile = New FileInfo(mOpenDialog.FileName)
            End If
        End Sub
#End Region

        Public Sub New()
            Source = New Parser()
            Init()
        End Sub

        Public Sub New(ByVal mFileInfo As FileInfo)
            Source = LoadParser(mFileInfo)
            SaveFile = mFileInfo.FullName
            Init()
        End Sub

        Public Sub Init()
            AddHandler PropertyChanged, Sub() IsSaved = False
            AddHandler Source.InputHeaderInfo.PropertyChanged, Sub() NotifyPropertyChanged(Function() InputFileParseLine)
        End Sub

        Public Shared Function LoadParser(ByVal mFileInfo As FileInfo) As Parser
            Try
                Dim xmlParser As New XmlDataModel.Parser()
                xmlParser.FromXmlFile(mFileInfo.FullName)
                Dim baseParser As New Parser()
                baseParser.InjectFrom(New ParserInjectionXml(baseParser, xmlParser), xmlParser)
                Return baseParser
            Catch ex As Exception
                MessageBox.Show(String.Format("Could not open parser: {0}", ex.Message))
                Return New Parser()
            End Try
        End Function

        Public Sub Save()
            If String.IsNullOrEmpty(SaveFile) Then
                Dim mSaveDialog = SaveDialog
                If mSaveDialog.ShowDialog() Then
                    SaveFile = mSaveDialog.FileName
                Else
                    Return
                End If
            End If
            IsSaved = Save(SaveFile)
        End Sub

        Public Function Save(ByVal mFilePath As String) As Boolean
            SaveFile = mFilePath
            Return SaveParser(mFilePath, Source)
        End Function

        Public Shared Function SaveParser(ByVal mFilePath As String, ByVal mParser As Parser) As Boolean
            If Not mParser.IsValid Then
                Return False
            End If

            Try
                Dim xmlParser As New XmlDataModel.Parser()
                xmlParser.InjectFrom(New ParserInjectionXml(mParser, xmlParser), mParser)
                xmlParser.ToXmlFile(mFilePath)
                Return True
            Catch ex As Exception
                MessageBox.Show(String.Format("Could not save parser: {0}", ex.Message))
                Return False
            End Try
        End Function
    End Class
End Namespace

What I am wondering is, if there is a better way to structure the view model to improve data binding, so I don't have to bind to Source.Name etc. How should I handle the base model in the view model?

Thanks, Alex.

It really depends.

If your Model already implements INotifyPropertyChanged and uses collection types that implement INotifyCollectionChanged, I personally feel that directly encapsulating and binding to "Source.Name" in XAML has some real advantages - mainly, it dramatically reduces the amount of code, and it (more importantly) reduces the amount of unnecessary code duplication.

However, Model classes often aren't designed specifically with WPF or Silverlight support in mind, and require wrapping. As soon as you have to wrap parts of the Model into the ViewModel for handling specific notifications, wrapping the entire model leads to more consistency.

This really has a cost-benefit trade-off to consider. If you're working with a different designer, wrapping everything leads to consistency in the API (that the designer uses), which can help reduce bugs (at the cost of some extra duplication on your part). If you're doing everything, then it's really up to you what makes the most sense.

Do I have to lock the database connections when multithreading?

2 votes

Here is a sample of the class I currently use for database interaction:

using System;
using System.Data;
using System.Collections.Generic;

// Libraries
using log4net;
using log4net.Config;
using MySql.Data.MySqlClient;

namespace AIC
{
    class DB
    {
        private static readonly ILog _logger = LogManager.GetLogger(typeof(DB));
        private MySqlConnection _connection;
        private MySqlCommand _cmd;
        private string _server;
        private string _database;
        private string _username;
        private string _password;

        //Constructor
        public DB(string server, string database, string username, string password)
        {
            log4net.Config.XmlConfigurator.Configure();

            _server = server;
            _database = database;
            _username = username;
            _password = password;

            _connection = new MySqlConnection(string.Format("SERVER={0};DATABASE={1};UID={2};PASSWORD={3};charset=utf8;", _server, _database, _username, _password));
        }

        public bool TestConnection()
        {
            try
            {
                _connection.Open();
                _connection.Close();
                _logger.Info("Connection test, passed...");
                return true;
            }
            catch (MySqlException ex)
            {
                _logger.Error(ex.ToString());
                return false;
            }
        }

        //open connection to database
        private bool Open()
        {
            try
            {
                if (_connection.State != ConnectionState.Open)
                    _connection.Open();
                _logger.Info("Starting connection to database...");
                return true;
            }
            catch (MySqlException ex)
            {
                _logger.Error(ex.ToString());
                return false;
            }
        }

        //Close connection
        private bool Close()
        {
            try
            {
                if (_connection.State != ConnectionState.Closed)
                    _connection.Close();
                _logger.Info("Closing connection to database...");
                return true;
            }
            catch (MySqlException ex)
            {
                _logger.Error(ex.ToString());
                return false;
            }
        }

        // Some basic functions
        public bool UserExist(string user)
        {
            string query = "SELECT user_id FROM users WHERE username=@name LIMIT 1";
            if (this.Open())
            {
                try
                {
                    // Assign the connection
                    _cmd = new MySqlCommand(query, _connection);

                    // Prepare to receive params
                    _cmd.Prepare();

                    // Fill up the params
                    _cmd.Parameters.AddWithValue("@name", user);

                    // returned count bool
                    bool result = Convert.ToInt32(_cmd.ExecuteScalar()) > 0;

                    // Close connection
                    this.Close();
                    return result;
                }
                catch (MySqlException ex)
                {
                    _logger.Error(ex.ToString());
                    this.Close();
                    return false;
                }
            }
            else
            {
                _logger.Error("You must be connected to the database before performing this action");
                return false;
            }
        }

        public bool AddUser(string user)
        {
            // .... add user to database
        }

        public bool DelUser(string user)
        {
            // .... del user from database
        }

        public int CountUsers()
        {
            // .... count total users from database
        }
    }
}

Currently, I don't have any management for opening and closing the connections so it will always check wether the database is connected or not, perform the action and close it as shown in the UserExist function.

Considering this, it came to my attention that I might be closing my own connections in the middle or their transactions since I am using this in 2 different threads.

My doubt here is wether this simple class could lock my application for any reason making it unresponsive or cause me any troubles in the long run?

What should I consider, improve, etc.?

Would appreciate code samples.

Each thread should have its own connection instance, in your case probably an instance of Db.

But the problem would be solved (a lot) better by not storing a connection in your Db objects at all. The best pattern is to only use connections as local variables in a using() {} statement.

Currently, your class should implement IDisposable (just for the case where your try/catch logic fails).