开发者

Set anonymous type to null

I know it's not allowed to set an nonymous type to null, but how do I solve this:

var products = null; //this cant be null, but somehow it must be declared in this outer scope, and not only inside the try-catch scope

    try
     {
         products = (from p in repository.Products
                     select new { p.Product, p.ProductName }).开发者_如何学运维ToList();
     }
     catch (Exception e)
     {  
       return;
     }
Console.WriteLine(products.FirstOrDefault().ProductName)


I agree with the other answers that you should consider refactoring this code or using a nominal type rather than an anonymous type.

However, there is a way to get a null reference in a variable of anonymous type. It's easy.

static List<T> GimmeANullListOf<T>(T t) { return (List<T>)null; }
...
var products = GimmeANullListOf(new { X = 1, Y = "hello" });

This trick is called "cast by example", and it is weird but legal.


Or new Nullable<bool>() will get the job done nicely.


For something that simple, and for the fact that you return on exception, you should be able to just do everything in the try block instead of having to declare products outside it:

try
{
    var products = (from p in repository.Products
                    select new { p.Product, p.ProductName }).ToList();
    Console.WriteLine(products.FirstOrDefault().ProductName);
}
catch (Exception e)
{  
    return;
}

Although I agree very much with SLaks, you shouldn't swallow exceptions and return like that.


There's no simple way round that. Your choices are either to change the control flow to wrap the whole thing in your try{} block (trivial in this case, but I assume this code is simplified for illustrative purposes), or do declare a concrete type such as

class ProductWithName
{
    public int Product;
    public string ProductName;
}

and then use

List<ProductWithName> products = null;

and

select new ProductWithName { Product = p.Product, ProductName = p.ProductName }

Which is the best option really depends on what your real code looks like.


What you want is to use an anonymous type outside its declaring scope.

You can do it with reflection:

IEnumerable<object> products = null;

// ...

var anon = products.FirstOrDefault();
Console.WriteLine(anon.GetType().GetProperty("ProductName").GetValue(anon, null));

Or dynamic:

IEnumerable<dynamic> products = null;

// ...

var anon = products.FirstOrDefault();
Console.WriteLine(anon.ProductName);


It's not the anonymous type that can't be null, it's the IEnumerable<T>(or IQueryable) that must not be null since you iterate over it.

You can use products ?? Enumerable.Empty<Product>() to replace null by an empty IEnumerable<T>.

And don't swallow exceptions like that. Catching the Exception base-class is only a good idea in very specific scenarios, and yours isn't one of them.


Since LINQ has deferred execution you can define the query in the parent scope and run it in the try catch block like so:

var productsDB = new List<Func<string>>() { () => "Apples", () => "Pears", () => "Bannanas" };//, () => { throw new NotImplementedException(); } }; // sorry, couldn't think of a better way to make this fail in 2 mins..

var products = (
    from p in productsDB
    select new 
    {
        Name = p()
    } );

try
{
    products.ToList(); // runs the LINQ query
    products.Dump();   // prints the results (LINQPad)
}
catch { "there was an error".Dump(); }

Or another option is the Tuple class, which is excellent for this kind of thing:

var productsDB = new[] { "Apples", "Pears",  "Bannanas" };

List<Tuple<string>> products;

try
{
    products = (
        from p in productsDB
        select Tuple.Create( p ) ).ToList();

    products.Dump();
}
catch { "there was an error".Dump(); }

// Build anonymous type from (read-only) Tuple here if necessary...

EDIT: Just realised I mis-read the post :p - heres my original post:

I think it's just the type-checker complaining, try something like this..

var employees = (
    from person in db.denormalisedPeople
    where person.Type == "employee"
    select new
    {
        name = employee.FullName,
        areaID = new Nullable<int>(), // placeholder.. set in a future query                
    } ).ToList();

(untested code, but the technique works fine for me)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜