2011-01-23 5 views
3

Я знаю, что это не разрешено установить nonymous тип обнулить, но как я могу решить эту проблему:Установите анонимный тип обнулить

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) 

ответ

11

Я согласен с другими ответами, которые вы должны рассмотреть, переформатируя этот код или используя номинальный тип, а не анонимный тип.

Однако есть способ получить нулевую ссылку в переменной анонимного типа. Это просто.

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

Этот трюк называется «литой на пример», и это странно, но легально.

+1

Но он учитывает внутренние знания компилятора, что может быть неверным для других компиляторов или для будущих версий компилятора. (Конечно, _you_ может сделать это верным для компилятора Microsoft C# ...) Или ... это где-то в спецификации? Будет ли это работать через собрания? –

+3

@ Jordão: Я не буду следовать за тобой. Как следует учитывать внутренние знания компилятора? Это законный C#, и любая соответствующая реализация должна иметь такое поведение. Почему вы считаете, что это поведение, определяемое реализацией? Что «будет ли это работать через собрания?» имею в виду? Я не понимаю, что значит «работать» в вашем вопросе. –

+0

@ Jordão: Если вы «работаете через сборки», вы имеете в виду, что у вас есть два метода в двух сборках, которые возвращают «идентичные» объекты анонимного типа, не могли бы вы рассматривать их как один и тот же тип, а затем нет. Спецификация C# заявляет, что анонимные типы гарантируются только в рамках единой компиляции. –

2

За то, что простой, и за то, что вы return на исключение, вы должны быть в состоянии просто делать все, что в try блоке вместо того, чтобы объявить products за его пределами:

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

Хотя я согласен с очень SLaks, вы не должны проглотить исключений и вернуться, как это.

+2

Это будет проглотить слишком много исключений. – SLaks

+0

Да, действительно. Код упрощен, я думал, что это было достаточно ясно. Но, в любом случае, спасибо. – Buginator

1

Это не анонимный тип, который не может быть нулевым, это IEnumerable<T> (или IQueryable), который не должен быть пустым, поскольку вы перебираете его.

Вы можете использовать products ?? Enumerable.Empty<Product>(), чтобы заменить null пустым IEnumerable<T>.

И не проглатывайте подобные исключения. Захват базового класса Exception - это только хорошая идея в очень специфических сценариях, и ваш не является одним из них.

+0

Я считаю, что для этого требуется специальный класс Product, который я хотел бы избежать. Мой код сильно упрощен, поэтому я понимаю, почему вы выбрали подход Product-class. – Buginator

1

Вы хотите использовать анонимный тип вне его области объявления.

Вы можете сделать это с отражением:

IEnumerable<object> products = null; 

// ... 

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

или динамический:

IEnumerable<dynamic> products = null; 

// ... 

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

Это классно, но не проверено, но оно кажется законным. Но по соображениям производительности это не может быть использовано в этом случае. – Buginator

+0

Эксплуатационные характеристики 'dynamic' могут [удивить вас] (http://geekswithblogs.net/SunnyCoder/archive/2009/06/26/c-4.0-dynamics-vs.-reflection.aspx). –

2

Там нет простого способа раунда это. Ваш выбор либо изменить поток управления, чтобы обернуть все это в вашем try{} блоке (в этом случае тривиален, но я предполагаю, что этот код упрощен для иллюстративных целей), или же объявить конкретный тип, такие как

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

, а затем использовать

List<ProductWithName> products = null; 

и

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

Какой лучший вариант действительно зависит от того, что ваш реальный код выглядит следующим образом.

+0

Вы правы, код сильно упрощен, и я сам думал об этом решении. Тем не менее, я хотел избежать создания нового класса только для этого. Но это сработало бы. – Buginator

0

Поскольку LINQ отложила выполнение можно определить запрос в родительской области и запустить его в сточный блоке Ьгу так:

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(); } 

Или другой вариант является класс Кортеж, который отлично подходит для такого рода вещи:

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: Просто понял, что я неправильно прочитал пост: р - мой первоначальный Херес пост:

Я думаю, что это просто типа проверки жалуюсь, попробовать что-то вроде этого ..

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(); 

(непроверенный код, но техника отлично работает для меня)

Смежные вопросы