Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return type T can't be returned as null? C# Generics

I have a method that generically deserializes a stored object from a users provided filepath and object type. The method works fine, except for when the user provides an invalid filepath. I would like my method to return a null in this case, but when I attempt to return null I get a compilation error. I tried to use a nullable type but get a compilation error. Instead, I typecast an object and return that, but it causes a runtime error. I would like to know if anyone knows the proper way to allow for returning a null. The code is as follows:

        public static T RestoreObj<T>(string datafile)
    {


        try
        {
            var fs = File.OpenRead(datafile);
            var bf = new BinaryFormatter();
            var obj = (T) bf.Deserialize(fs);
            fs.Close();
            return obj;
        }
        catch (Exception e)
        {
            MessageBox.Show("Could not load. Accepts valid *.dom files only. " + e);

            // TODO: how to do this? this will throw a runtime error, and if null returned, a compilation error
            var o = new object();
            return (T) o;
        }
    }

After taking Eric Lippert's quality comments in to consideration I revised the method to look like what you see below. The advantage of using 'using' is that it automatically generates a try..finally block that will call the dispose method (FileStream implements IDisposable, if it did not their would be a compile error). Another nice thing is that the exception thrown is relevant to whatever is actually happening instead of what I have above.

        public static T RestoreObj<T>(string datafile) 
    {
        using (var fs = File.OpenRead(datafile))
        {
            var bf = new BinaryFormatter();
            var obj = (T)bf.Deserialize(fs);
            return obj;
        }
    }
like image 890
sapbucket Avatar asked Sep 07 '11 20:09

sapbucket


People also ask

Can we return null in C?

NULL can be used if a function returns a pointer. In this case, you return an object, which means that you have to return a real, existing object. One way of doing this is to have an "ok" field in the struct that you could set in the init function, and that you could check in the caller.

What does return null mean in C?

No. return is used to "break" out from a function that has no return value, i.e. a return type of void . return NULL returns the value NULL , and the return type of the function it's found in must be compatible with NULL .

How do I return a generic null?

So, to return a null or default value from a generic method we can make use default(). default(T) will return the default object of the type which is provided.

Can you return null in an int function?

The data type of the return value is the same as that of the number parameter. If the numeric expression results in a null, Int returns a null.

Why can’t I return NULL in C++?

Cannot convert null to type parameter ‘T’ because it could be a non-nullable value type. Consider using ‘default (T)’ instead You can’t return null because the compiler doesn’t know if T is nullable.

Can a null reference be returned from a return type?

Hence, an array or an object of any class can be returned from a method with the Object return type. A null reference means a reference which is currently not pointing to any object on the Heap but it has the capability to point to an object in the future. Hence, a null reference can be returned from a method with a return type of any class.

Why can’t I return Null from a generic method?

You’re trying to return null from a generic method and you’re getting the following compiler error: Cannot convert null to type parameter ‘T’ because it could be a non-nullable value type. Consider using ‘default (T)’ instead You can’t return null because the compiler doesn’t know if T is nullable.

Is it possible to return Null from a pointer?

It is not an int, so a function returning int cannot return NULL. Now, it is possible to convert NULL or any other pointer to type int, but the result of such a conversion is a valid, ordinary int. You seem to be looking instead for some kind of distinguished value, but there is none available unless you reserve such a value yourself.


2 Answers

If you're only going to work with classes, then add the where T : class constraint:

public static T RestoreObj<T>(string datafile) where T : class

If you expect to deserialize structs as well, then just return default(T). That will be null for reference types, and the default value (usually 0) for structs. As @JMH points out, default(Nullable<T>) is a null-containing nullable.

like image 89
dlev Avatar answered Oct 21 '22 07:10

dlev


I would solve the problem by not writing that code in the first place.

A method should do one thing and do it well; you are mixing up deserialization code with error reporting code.

Don't do that. A better way would be to have the deserialization method throw an exception, and write different code that handles the exceptions and reports errors to the user.

More generally, it is dangerous to have a method that eats exceptions and then returns bogus data. That is just creating problems down the line when unsuspecting code that calls your method expects to get good data back.

While we're on the subject of code quality, you should be using "using" blocks to ensure that the file handles are closed if an exception happens. Do not explicitly do a fs.Close() -- rather, do using(var fs = ... ) and let the compiler generate the disposal that closes the file.

like image 38
Eric Lippert Avatar answered Oct 21 '22 06:10

Eric Lippert