1

I've got the task convert variable of nullable type to not nullable if it's nullable and redefine default values for types, if it's required. I wrote generic static class for it, but, unfortunately, it works to slow. This class will be used in reading data from database to model, so performance is very important. Here is my class.

public static class NullableTypesValueGetter<T> where T : struct
{
    #region [Default types values]
    private static DateTime currentDefaultDateTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
    #endregion

    #region [Default types to string values]
    private const string nullableDateTimeValue = "DateTime?";
    #endregion

    public static T GetValue(dynamic value) 
    {
        if (Nullable.GetUnderlyingType(value.GetType()) != null)                           //if variable is nullable
        {
            var nullableValue = value as T?;
            //if variable has value
            if (nullableValue.HasValue)                                                    
            {
                return nullableValue.Value;
            }
            //if hasn't
            else                                                                          
            {
                var result = default(T);
                //extensionable code, determination default values
                var @switch = new Dictionary<Type, string>
                {
                    {typeof(DateTime?), nullableDateTimeValue}                            
                };
                //redefining result, if required
                if (@switch.Any(d => d.Key.Equals(nullableValue.GetType())))              
                {
                    switch (@switch[nullableValue.GetType()])
                    {
                        //extensionable code
                        case (nullableDateTimeValue):                                    
                        {
                            result = GetDefaultDateTimeValue();
                        } break;
                    }

                }

                return result;
            }
        }
        //if not nullable
        else                                                                              
        {
            return value;
        }
    }

    private static T GetDefaultDateTimeValue()
    {
        return (T)Convert.ChangeType(new DateTime?(currentDefaultDateTime), typeof(T));
    }
}

Do you know any others realizations of this class or any ways to improve performance of this?

Yael
  • 1,566
  • 3
  • 18
  • 25
  • Well of course it's slow. You're using `dynamic` which means you're re-compiling all of your code from scratch every time it runs. Don't do that, especially when you have no reason at all to do so. – Servy Dec 01 '16 at 15:04
  • `static T GetValue(Nullable nullable) { return nullable.HasValue ? nullable.Value : default(T); }` and for every `static T GetValue(object obj) { if(obj.GetType() == typeof(Nullable<>)) return GetValue(Nullable)obj); else ... your stuff with dictionary` – mrogal.ski Dec 01 '16 at 15:06
  • If you want to convert values from database to object, maybe Dapper is a good and fast solution for you: https://github.com/StackExchange/dapper-dot-net Will make it easier for you to handle all that stuff and you need less boilerplate. Every other ORM-Mapper will work as well. – Sebi Dec 01 '16 at 15:10
  • @Servy no it doesn't? Dynamic is a compile type construct and doesn't exist to the runtime. It creates a container to hold each implementation, but that's done at compile time. Nothing is recompiled at runtime. – Dispersia Dec 01 '16 at 15:15
  • 1
    @Dispersia All it does at compile time is write out code to run the compiler at runtime to determine what to actually do. Yes, it's a compile time construct, but it doesn't actually do much of anything at compile time. – Servy Dec 01 '16 at 15:17
  • @Dispersia `dynamic` in the parameter list translates to `object`, yes, but all invocations on `value` are performed using a runtime dynamic binder, being late bound. The only usage of `value` in the method are `as` and `GetType`. Both are valid and semantically the same for both `object` and `dynamic`, so switching to `object` makes the code faster and no less correct. – IS4 Dec 01 '16 at 15:21
  • @IllidanS4 Yes, im not disagreeing that it does in fact call `Create` on `CSharpArgumentInfoFlags` to create the type to be passed, that doesn't change the fact that it's just creating the type, it's not recompiling anything. That would be the same as saying casting an object is recompiling - that's just simply not true. The runtime is not changing it's already compiled code in any way for creating a new type. – Dispersia Dec 01 '16 at 15:25
  • 1
    @Dispersia Casting an object simply involved checking if the type of the object is identical to the type being cast to. Obviously that doesn't involve re-compiling the code at runtime. Performing any operation on a `dynamic` value actually spins up a compilers and performs the compiler's semantic analyzer on the operation to determine what it should actually do, because when the code was originally compiled it bound nothing, merely including the semantic information about the code. It actually does re-compile the code at runtime. – Servy Dec 01 '16 at 15:29
  • @Servy Your example of casting isn't true either, considering there are many different types of casting... what if it's a reference type? What if it's -not- the same type? (int to float), if that was the case, the CastClass opcode would never exist. When I get home I can write you a full example, just show me where you think it's doing this 'recompilation', because if you open dissassembly in visual studio, you can clearly see it's not doing what you think it's doing – Dispersia Dec 01 '16 at 15:36
  • @Dispersia You're talking about explicit conversions, not a cast, but either way, that's merely binding a conversion operator at compile time to be run at runtime, so at runtime the only thing happening is that that operator is being called. Performing an operation bound at compile time is not at all running the compiler at runtime. Of course, I don't see how any of that relates to the operations performed on a `dynamic` value. – Servy Dec 01 '16 at 15:41
  • @Servy https://msdn.microsoft.com/en-us/library/xhbhezf4.aspx `Unlike implicit conversion, explicit conversion operators must be invoked by means of a cast.` https://www.dotnetperls.com/explicit `Whenever you use a cast like (Apartment) or (House), this is an explicit cast.` What. I'm sorry there isn't a point continuing this conversation (and it should by now be in chat anyway). – Dispersia Dec 01 '16 at 15:44

2 Answers2

7

Why don't you simply use Nullable<T>.GetValueOrDefault?

int? val = null;
int newVal = val.GetValueOrDefault(-1); // result: -1
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
0

I haven't really thought about how to improve your code.

But I suggest you take an entirely different approach to improve performance. If you know the database schema or the data POCOs at compile time, instead of using reflection and determining the type to convert to at runtime you can produce strongly typed POCOs with non-nullable properties and the necessary conversion code by using T4 scripts.

This will always be considerably faster than using reflection at runtime.