Обновление 2015-12-15: см. https://stackoverflow.com/a/22864936/1718702 для C # 6. Это чище и теперь стандарт в языке.
Для тех, кто хочет, чтобы было более элегантное решение , чтобы перехватывать один раз и фильтровать исключения, я использую метод расширения, как показано ниже.
У меня уже было это расширение в моей библиотеке, изначально написанное для других целей, но оно отлично работало для type
проверки исключений. Плюс, имхо, это выглядит чище, чем куча ||
утверждений. Кроме того, в отличие от принятого ответа, я предпочитаю явную обработку исключений, поэтому ex is ...
имел нежелательное поведение, поскольку производные классы присваиваются родительским типам).
Использование
if (ex.GetType().IsAnyOf(
typeof(FormatException),
typeof(ArgumentException)))
{
// Handle
}
else
throw;
Расширение IsAnyOf.cs (см. Пример полной обработки ошибок для зависимостей)
namespace Common.FluentValidation
{
public static partial class Validate
{
///
/// Validates the passed in parameter matches at least one of the passed in comparisons.
///
///
/// Parameter to validate.
/// Values to compare against.
/// True if a match is found.
///
public static bool IsAnyOf(this T p_parameter, params T[] p_comparisons)
{
// Validate
p_parameter
.CannotBeNull("p_parameter");
p_comparisons
.CannotBeNullOrEmpty("p_comparisons");
// Test for any match
foreach (var item in p_comparisons)
if (p_parameter.Equals(item))
return true;
// Return no matches found
return false;
}
}
}
Пример полной обработки ошибок (копирование-вставка в новое консольное приложение)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.FluentValidation;
namespace IsAnyOfExceptionHandlerSample
{
class Program
{
static void Main(string[] args)
{
// High Level Error Handler (Log and Crash App)
try
{
Foo();
}
catch (OutOfMemoryException ex)
{
Console.WriteLine("FATAL ERROR! System Crashing. " + ex.Message);
Console.ReadKey();
}
}
static void Foo()
{
// Init
List> TestActions = new List>()
{
(key) => { throw new FormatException(); },
(key) => { throw new ArgumentException(); },
(key) => { throw new KeyNotFoundException();},
(key) => { throw new OutOfMemoryException(); },
};
// Run
foreach (var FooAction in TestActions)
{
// Mid-Level Error Handler (Appends Data for Log)
try
{
// Init
var SomeKeyPassedToFoo = "FooParam";
// Low-Level Handler (Handle/Log and Keep going)
try
{
FooAction(SomeKeyPassedToFoo);
}
catch (Exception ex)
{
if (ex.GetType().IsAnyOf(
typeof(FormatException),
typeof(ArgumentException)))
{
// Handle
Console.WriteLine("ex was {0}", ex.GetType().Name);
Console.ReadKey();
}
else
{
// Add some Debug info
ex.Data.Add("SomeKeyPassedToFoo", SomeKeyPassedToFoo.ToString());
throw;
}
}
}
catch (KeyNotFoundException ex)
{
// Handle differently
Console.WriteLine(ex.Message);
int Count = 0;
if (!Validate.IsAnyNull(ex, ex.Data, ex.Data.Keys))
foreach (var Key in ex.Data.Keys)
Console.WriteLine(
"[{0}][\"{1}\" = {2}]",
Count, Key, ex.Data[Key]);
Console.ReadKey();
}
}
}
}
}
namespace Common.FluentValidation
{
public static partial class Validate
{
///
/// Validates the passed in parameter matches at least one of the passed in comparisons.
///
///
/// Parameter to validate.
/// Values to compare against.
/// True if a match is found.
///
public static bool IsAnyOf(this T p_parameter, params T[] p_comparisons)
{
// Validate
p_parameter
.CannotBeNull("p_parameter");
p_comparisons
.CannotBeNullOrEmpty("p_comparisons");
// Test for any match
foreach (var item in p_comparisons)
if (p_parameter.Equals(item))
return true;
// Return no matches found
return false;
}
///
/// Validates if any passed in parameter is equal to null.
///
/// Parameters to test for Null.
/// True if one or more parameters are null.
public static bool IsAnyNull(params object[] p_parameters)
{
p_parameters
.CannotBeNullOrEmpty("p_parameters");
foreach (var item in p_parameters)
if (item == null)
return true;
return false;
}
}
}
namespace Common.FluentValidation
{
public static partial class Validate
{
///
/// Validates the passed in parameter is not null, throwing a detailed exception message if the test fails.
///
/// Parameter to validate.
/// Name of tested parameter to assist with debugging.
///
public static void CannotBeNull(this object p_parameter, string p_name)
{
if (p_parameter == null)
throw
new
ArgumentNullException(
string.Format("Parameter \"{0}\" cannot be null.",
p_name), default(Exception));
}
}
}
namespace Common.FluentValidation
{
public static partial class Validate
{
///
/// Validates the passed in parameter is not null or an empty collection, throwing a detailed exception message if the test fails.
///
///
/// Parameter to validate.
/// Name of tested parameter to assist with debugging.
///
///
public static void CannotBeNullOrEmpty(this ICollection p_parameter, string p_name)
{
if (p_parameter == null)
throw new ArgumentNullException("Collection cannot be null.\r\nParameter_Name: " + p_name, default(Exception));
if (p_parameter.Count <= 0)
throw new ArgumentOutOfRangeException("Collection cannot be empty.\r\nParameter_Name: " + p_name, default(Exception));
}
///
/// Validates the passed in parameter is not null or empty, throwing a detailed exception message if the test fails.
///
/// Parameter to validate.
/// Name of tested parameter to assist with debugging.
///
public static void CannotBeNullOrEmpty(this string p_parameter, string p_name)
{
if (string.IsNullOrEmpty(p_parameter))
throw new ArgumentException("String cannot be null or empty.\r\nParameter_Name: " + p_name, default(Exception));
}
}
}
Два примера модульных тестов NUnit
Соответствие поведения для типов Exception
: точный (т. е. дочерний элемент НЕ соответствует ни одному из родительских типов).
using System;
using System.Collections.Generic;
using Common.FluentValidation;
using NUnit.Framework;
namespace UnitTests.Common.Fluent_Validations
{
[TestFixture]
public class IsAnyOf_Tests
{
[Test, ExpectedException(typeof(ArgumentNullException))]
public void IsAnyOf_ArgumentNullException_ShouldNotMatch_ArgumentException_Test()
{
Action TestMethod = () => { throw new ArgumentNullException(); };
try
{
TestMethod();
}
catch (Exception ex)
{
if (ex.GetType().IsAnyOf(
typeof(ArgumentException), /*Note: ArgumentNullException derrived from ArgumentException*/
typeof(FormatException),
typeof(KeyNotFoundException)))
{
// Handle expected Exceptions
return;
}
//else throw original
throw;
}
}
[Test, ExpectedException(typeof(OutOfMemoryException))]
public void IsAnyOf_OutOfMemoryException_ShouldMatch_OutOfMemoryException_Test()
{
Action TestMethod = () => { throw new OutOfMemoryException(); };
try
{
TestMethod();
}
catch (Exception ex)
{
if (ex.GetType().IsAnyOf(
typeof(OutOfMemoryException),
typeof(StackOverflowException)))
throw;
/*else... Handle other exception types, typically by logging to file*/
}
}
}
}
Думаю, если у вас есть функция, которая принимает имя файла в качестве аргумента и возвращает содержимое этого файла - вы можете использовать эту функцию в формуле Crystal Report.
Я не знаком с текущим CR, прошло много лет с тех пор, как я последний раз его использовал (последний раз использовал версию 8). В тех версиях, которые я использовал, такая функция не была встроена. Тогда вам нужно было бы создать UFL (библиотеку пользовательских функций), содержащую нужные вам функции. Если я правильно помню, вам приходилось делать это с помощью COM.
В наши дни, я думаю, вы можете расширить CR, используя какой-то другой механизм, например, написав код .NET?
Я предлагаю вам поискать в документации CR для термин UFL.
Другое предложение, затем:
You would need to set up a file dsn (in XP it's under Control Panel/Administrative Tools/Datasources (ODBC)) and then use the file dsn (Microsoft Text Driver) for the datasource as an ODBC(RDO) connection.
I set this test scenario up on mine like the following:
**File 1**
column1
1row1
1row2
1row3
**File 2**
column1
2row1
2row2
2row3
I set up the file dsn to point to the c drive and in the datasource screen I added file1.txt and file2.txt to the selected tables. Then the easiest thing to do is clear the links of the tables so that it pulls every row. It will warn you that there are multiple starting points. I don't generally recomend this, but it will work in this case and since it's not reporting off a database it probably isn't the end of the world. If you disregard the starting point message then add the fields to the report, when you run it you should get the following output:
1row1 2row1
1row1 2row2
1row1 2row3
1row2 2row1
1row2 2row2
1row2 2row3
1row3 2row1
1row3 2row2
1row3 2row3
From this you can change your grouping to get the output that you need.
You can also use this same connect against subreports instead of doing this linking where you have the main report pull the info from file1.txt and then put a subreport in the report footer that pulls from file2.txt. This option won't have the text collated, but you'd still have it in the same report.
Hope this helps some.
Вы можете настроить файл dsn. Но это ориентировано на данные табличного файла, а не на текст.
Насколько велики эти текстовые файлы? Вы хотите отобразить все содержимое каждого файла?
Вероятно, нет простого способа динамического чтения файла из кристалла. Скорее всего, вам придется отправить набор данных в отчет, содержащий содержимое файла.
Это проще, чем вы думаете. Я просто установил один перед тем, как написать это, чтобы убедиться, что я даю вам правильные шаги. Используя CR версии XI и файл .txt, я выполнил следующие шаги: