Testing whether an abstract object is an instance of one of the several concrete classes
Assuming that you have a good reason for not having an overriden GetValue() method on each sub-class, an extension method for each class, say, GetValue() should solve it.

public static class ObserverExtensions
{
  private static readonly IDictionary&lt;Type, Func&lt;ObserverDto, string&gt;&gt; _lookup = new Dictionary&lt;Type, Func&lt;ObserverDto, string&gt;&gt;
  {
     {typeof(BooleanObserverDto), dto =&gt; ((BooleanObserverDto)dto).GetValue() },
     {typeof(IntObserverDto), dto =&gt; ((IntObserverDto)dto).GetValue() },
     {typeof(DecimalObserverDto), dto =&gt; ((DecimalObserverDto)dto).GetValue() },
     {typeof(StringObserverDto), dto =&gt; ((StringObserverDto)dto).GetValue() },
  };

  public static string GetValue(this ObserverDto observerDto)
  {
       return _lookup[observerDto.GetType()](observerDto);
  }

  public static string GetValue(this BooleanObserverDto booleanObserverDto)
  {
     return booleanObserverDto.CurrentValue == true ? booleanObserverDto.TrueText :
            booleanObserverDto.CurrentValue == false ? booleanObserverDto.FalseText : booleanObserverDto.CurrentValue.ToString();
  }

  public static string GetValue(this IntObserverDto intObserverDto)
  {
     return intObserverDto.CurrentValue.ToString();
  }

  public static string GetValue(this DecimalObserverDto decimalObserverDto)
  {
     return Convert.ToSingle(decimalObserverDto.CurrentValue).ToString(CultureInfo.CurrentCulture);
  }

  public static string GetValue(this StringObserverDto stringObserverDto)
  {
     return stringObserverDto.CurrentValue;
  }
}


//...
Value = ObserverDto.GetValue();


One nice thing about this solution  is that we can add more classes (say, DateTimeObserverDto) without having to open up the set/update code. We simply add another extension method.

Edit: Correction

The extension methods only work if the references to the objects are of the concrete type. It doesn't work when passing in ObserverDto objects

// Passed
[TestMethod]
public void CheckConversions()
{
     var a = new IntObserverDto { CurrentValue = 17 };
     var b = new DecimalObserverDto { CurrentValue = 19.1m };
     var c = new BooleanObserverDto { CurrentValue = false };
     var d = new StringObserverDto { CurrentValue = "Hello World" };

     Assert.AreEqual("Hello World", d.GetValue());
     Assert.AreEqual("False", c.GetValue());
     Assert.AreEqual("19.1", b.GetValue());
     Assert.AreEqual("17", a.GetValue());
}

// Fails (doesn't compile) - no GetValue() for ObserverDto
[TestMethod]
public void CheckConversions()
{
     ObserverDto a = new IntObserverDto { CurrentValue = 17 };

     Assert.AreEqual("17", a.GetValue());
}


Best I can think of (sans adding a virtual method to ObserverDto) is use a lookup in the extension method (see above)