Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to use out variables in calls within LINQ statements?

Tags:

c#

linq

I have never done this before, and while I can't think of a specific reason that it would break, I'd like to verify that it is valid to use an out variable as follows:

void Main()
{
    var types = new [] { typeof(A), typeof(B) };
    bool b = false;
    var q = from type in types
            from property in type.GetProperties()
            let propertyName = GetName(property, out b)
            select new {
                TypeName = type.Name,
                PropertyName = propertyName,
                PropertyType = property.PropertyType.Name,
                IsNullable = b
            };
    q.Dump();
}

private string GetName(PropertyInfo property, out bool isNullable)
{
    string typeName;
    isNullable = false;
    var type = property.PropertyType;
    if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
    {
        isNullable = true;
        typeName = type.GetGenericArguments().First().Name;
    }
    else
    {
        typeName = property.Name;
    }
    return typeName;
}
like image 847
Aaron Anodide Avatar asked May 10 '12 21:05

Aaron Anodide


1 Answers

This will work - provided you actually fully evaluate the query.

However, the behavior will be very odd, and would be something I would strongly avoid. Since the out parameter is being used directly within the query, the behavior will be fairly normal here (provided you don't do anything else with this), but that is specific to this use case, not a general "rule" with using out mixed with LINQ.

The problem is that LINQ's deferred execution will cause the out parameter to get set, but only when you use the resulting enumerable, not when you declare it. This can cause very unexpected behavior, and lead to difficult to maintain and understand software.

I would personally just write a separate method, and use it to allow your query to be written as:

var q = from type in types 
        from property in type.GetProperties() 
        let propertyName = GetName(property)
        let nullable = GetIsNullable(property)
        // ...

This is much more clear, and less prone to mistakes and errors. It will also work with parallelization (ie: PLINQ via .AsParallel()) and other techniques if somebody tries to change this later.

like image 158
Reed Copsey Avatar answered Oct 29 '22 03:10

Reed Copsey