Мы реализуем шаблон опроса в ASP.NET, который может применяться к вашему варианту использования.
В нашем Global.ashx
мы имеем:
protected void Application_Start(object sender, EventArgs e)
{
ConfigurationMonitor.Start();
}
где ConfiguraitonMonitor
выглядит примерно так:
public static class ConfigurationMonitor
{
private static readonly Timer timer = new Timer(PollingInterval);
public static bool MonitoringEnabled
{
get
{
return ((timer.Enabled || Working) ? true : false);
}
}
private static int _PollingInterval;
public static int PollingInterval
{
get
{
if (_PollingInterval == 0)
{
_PollingInterval = (Properties.Settings.Default.ConfigurationPollingIntervalMS > 0) ? Properties.Settings.Default.ConfigurationPollingIntervalMS : 5000;
}
return (_PollingInterval);
}
set { _PollingInterval = value; }
}
private static bool _Working = false;
public static bool Working
{
get { return (_Working); }
}
public static void Start()
{
Start(PollingInterval);
}
/// <summary>
/// Scans each DLL in a folder, building a list of the ConfigurationMonitor methods to call.
/// </summary>
private static List<ConfigurationMonitorAttribute> _MonitorMethods;
private static List<ConfigurationMonitorAttribute> MonitorMethods
{
get
{
if (_MonitorMethods == null)
{
_MonitorMethods = new List<ConfigurationMonitorAttribute>();
MonitorMethodsMessage = string.Empty;
foreach (var assemblyFile in Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"), Properties.Settings.Default.ConfigurtionMonitorDLLPath))
{
var assembly = Assembly.LoadFrom(assemblyFile);
foreach (ConfigurationMonitorAttribute monitor in assembly.GetCustomAttributes(typeof(ConfigurationMonitorAttribute), inherit: false))
{
_MonitorMethods.Add(monitor);
}
}
}
return (_MonitorMethods);
}
}
/// <summary>
/// Resets and instanciates MonitorMethods property to refresh dlls being monitored
/// </summary>
public static void LoadMonitoringMethods()
{
_MonitorMethods = null;
List<ConfigurationMonitorAttribute> monitorMethods = MonitorMethods;
}
/// <summary>
/// Initiates a timer to monitor for configuration changes.
/// This method is invoke on web application startup.
/// </summary>
/// <param name="pollingIntervalMS"></param>
public static void Start(int pollingIntervalMS)
{
if (Properties.Settings.Default.ConfigurationMonitoring)
{
if (!timer.Enabled)
{
LoadMonitoringMethods();
timer.Interval = pollingIntervalMS;
timer.Enabled = true;
timer.Elapsed += new ElapsedEventHandler(OnTimerElapsed);
timer.Start();
}
else
{
timer.Interval = pollingIntervalMS;
}
}
}
public static void Stop()
{
if (Properties.Settings.Default.ConfigurationMonitoring)
{
if (timer.Enabled)
{
timer.Stop();
}
}
}
/// <summary>
/// Monitors CE table for changes
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
timer.Enabled = false;
PollForChanges();
timer.Enabled = true;
}
public static DateTime PollForChanges()
{
LastPoll = PollForChanges(LastPoll);
return (LastPoll);
}
public static DateTime PollForChanges(DateTime lastPollDate)
{
try
{
_Working = true;
foreach (ConfigurationMonitorAttribute monitor in MonitorMethods)
{
try
{
lastPollDate = monitor.InvokeMethod(lastPollDate);
if (lastPollDate > LastRefreshDate)
LastRefreshDate = lastPollDate;
}
catch (System.Exception ex)
{
// log the exception; my code omitted for brevity
}
}
}
catch (System.Exception ex)
{
// log the exception; my code omitted for brevity
}
finally
{
_Working = false;
}
return (lastPollDate);
}
#region Events
/// <summary>
/// Event raised when an AppDomain reset should occur
/// </summary>
public static event AppDomainChangeEvent AppDomainChanged;
public static void OnAppDomainChanged(string configFile, IDictionary<string, object> properties)
{
if (AppDomainChanged != null) AppDomainChanged(null, new AppDomainArgs(configFile, properties));
}
#endregion
}
Когда у нас есть сценарий использования, который хочет чтобы «участвовать» в этом механизме опроса, мы помечаем некоторый метод с атрибутом:
[assembly: ConfigurationMonitorAttribute(typeof(bar), "Monitor")]
namespace foo
{
public class bar
{
public static DateTime Monitor(DateTime lastPoll)
{
// do your expensive work here, setting values in your cache
}
}
}
Наш паттерн с методом, вызванным
blockquote>ConfigurationMonitor
, возвращающимDateTime
, был довольно странным краем дело. Конечно, вы могли бы пойти сvoid
методом.где
ConfigurationMonitorAttribute
примерно такой:[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class ConfigurationMonitorAttribute : Attribute { private Type _type; private string _methodName; public ConfigurationMonitorAttribute(Type type, string methodName) { _type = type; _methodName = methodName; } public Type Type { get { return _type; } } public string MethodName { get { return _methodName; } } private MethodInfo _Method; protected MethodInfo Method { get { if (_Method == null) { _Method = Type.GetMethod(MethodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); if (_Method == null) throw new ArgumentException(string.Format("The type {0} doesn't have a static method named {1}.", Type, MethodName)); } return _Method; } } public DateTime InvokeMethod(DateTime lastPoll) { try { return (DateTime)Method.Invoke(null, new object[] { lastPoll }); } catch (System.Exception err) { new qbo.Exception.ThirdPartyException(string.Format("Attempting to monitor {0}/{1} raised an error.", _type, _methodName), err); } return lastPoll; } }
Может быть, рекурсия?
public static void PrintNext(i) {
if (i <= 100) {
Console.Write(i + " ");
PrintNext(i + 1);
}
}
public static void Main() {
PrintNext(1);
}
static void Main(string[] args)
{
print(0);
}
public static void print(int i)
{
if (i >= 0 && i<=10)
{
i = i + 1;
Console.WriteLine(i + " ");
print(i);
}
}
namespace ConsoleApplication2 {
class Program {
static void Main(string[] args) {
Print(Enumerable.Range(1, 100).ToList(), 0);
Console.ReadKey();
}
public static void Print(List<int> numbers, int currentPosition) {
Console.WriteLine(numbers[currentPosition]);
if (currentPosition < numbers.Count - 1) {
Print(numbers, currentPosition + 1);
}
}
}
}
Это более или менее псевдокод, который я годами не писал на C #, PS работает в режиме сна 1 час, поэтому я могу ошибаться.
int i = 0;
public void printNum(j){
if(j > 100){
break;
} else {
print(j);
printNum(j + 1);
}
}
public void main(){
print(i);
printNum(i + 1);
}
PrintNum(1);
private void PrintNum(int i)
{
Console.WriteLine("{0}", i);
if(i < 100)
{
PrintNum(i+1);
}
}
Это похоже на не-одноэлементную версию паттерна модуля , в которой частные переменные можно моделировать, используя преимущества «замыканий» JavaScript.
Мне нравится ( вроде ... ). Но я действительно не вижу преимуществ в частных переменных, сделанных таким образом, особенно когда это означает, что любые новые добавленные методы (после инициализации) не имеют доступа к частным переменным.
Кроме того, он не использует преимущества прототипной модели JavaScript. Все ваши методы и свойства должны быть инициализированы КАЖДЫЙ раз при вызове конструктора - этого не происходит, если у вас есть методы, хранящиеся в прототипе конструктора. Дело в том, что использование обычного шаблона конструктор / прототип намного быстрее! Вы действительно думаете, что частные переменные позволяют снизить производительность?
Такой тип модели имеет смысл с шаблоном модуля, потому что он инициализируется только один раз (для создания псевдо-синглтона), но я не уверен, что это делает смысл здесь.
Используете ли вы этот тип шаблона конструктора?
Нет, хотя я использую его одноэлементный вариант, шаблон модуля ...
Считаете ли вы его понятным?
Да, он читается и довольно ясно, но мне не нравится идея сваливать все в один такой конструктор.
У вас есть лучший?
Если вам действительно нужны частные переменные, то обязательно придерживайтесь этого. В противном случае просто используйте стандартный шаблон конструктор / прототип (, если вы не разделяете опасения Крокфорда перед комбинацией new
/ this
):
Я могу думать двумя способами:
Console.WriteLine
goto
в операторе switch
К тому времени, как я отвечу на этот вопрос, он у кого-то уже будет, так что вот оно, в любом случае, с честью Калебу:
void Main()
{
print(0, 100);
}
public void print(int x, int limit)
{
Console.WriteLine(++x);
if(x != limit)
print(x, limit);
}
Я могу думать о двух способах. Один из них включает около 100 строк кода!
Есть другой способ многократно использовать немного кода без использования цикла while / for ...
Подсказка: создайте функцию, которая печатает числа от 1 до N . Должно быть легко заставить его работать для N = 1. Затем подумайте, как заставить его работать для N = 2.
Enumerable.Range(1, 100)
.Select(i => i.ToString())
.ToList()
.ForEach(s => Console.WriteLine(s));
Не уверен, что это считается скрытым циклом, но если он допустим, это идиоматическое решение проблемы. В противном случае вы можете это сделать.
int count = 1;
top:
if (count > 100) { goto bottom; }
Console.WriteLine(count++);
goto top;
bottom:
Конечно, это фактически то, во что будет транслироваться цикл в любом случае, но в наши дни, безусловно, не одобряется писать такой код.
Enumerable.Range(1, 100).ToList().ForEach(i => Console.WriteLine(i));
Вот разбивка того, что происходит в приведенном выше коде:
Рекомендации по производительности
Вызов ToList вызовет выделение памяти для всех элементов (в приведенном выше примере 100 целых значений). Это означает сложность пространства O (N). Если это вызывает беспокойство в вашем приложении, например, если диапазон целых чисел может быть очень большим, вам следует избегать ToList и перечислять элементы напрямую.
К сожалению, ForEach не является частью расширений IEnumerable, предоставляемых из коробки (следовательно, необходимо преобразовать в список в приведенном выше примере). К счастью, это довольно легко создать:
static class EnumerableExtensions
{
public static void ForEach<T>(this IEnumerable<T> items, Action<T> func)
{
foreach (T item in items)
{
func(item);
}
}
}
С указанным выше расширением IEnumerable теперь во всех местах, где вам нужно применить действие к IEnumerable, вы можете просто вызвать ForEach с лямбда-выражением. Итак, теперь исходный пример выглядит так:
Enumerable.Range(1, 100).ForEach(i => Console.WriteLine(i));
Единственное отличие состоит в том, что мы больше не вызываем ToList, и это приводит к постоянному (O (1)) использованию пространства ... что было бы весьма заметным выигрышем, если бы вы обрабатывали действительно большое количество предметов.
Еще одно:
Console.WriteLine(
String.Join(
", ",
Array.ConvertAll<int, string>(
Enumerable.Range(1, 100).ToArray(),
i => i.ToString()
)
)
);
Console.Out.WriteLine('1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100');
Console.WriteLine('1');
Console.WriteLine('2');
...
Console.WriteLine('100');
... Или вы бы приняли рекурсивное решение?
РЕДАКТИРОВАТЬ: или вы можете сделать это и использовать переменную:
int x = 1;
Console.WriteLine(x);
x+=1;
Console.WriteLine('2');
x+=1;
...
x+=1
Console.WriteLine('100');
Без циклов, без условных операторов и без жестко запрограммированного буквального вывода, также известное как решение «разделяй и властвуй FTW»:
class P
{
static int n;
static void P1() { System.Console.WriteLine(++n); }
static void P2() { P1(); P1(); }
static void P4() { P2(); P2(); }
static void P8() { P4(); P4(); }
static void P16() { P8(); P8(); }
static void P32() { P16(); P16(); }
static void P64() { P32(); P32(); }
static void Main() { P64(); P32(); P4(); }
}
Альтернативный подход:
using System;
class C
{
static int n;
static void P() { Console.WriteLine(++n); }
static void X2(Action a) { a(); a(); }
static void X5(Action a) { X2(a); X2(a); a(); }
static void Main() { X2(() => X5(() => X2(() => X5(P)))); }
}
Метод A:
Console.WriteLine('1');
Console.WriteLine('print 2');
Console.WriteLine('print 3');
...
Console.WriteLine('print 100');
Метод B:
func x (int j)
{
Console.WriteLine(j);
if (j < 100)
x (j+1);
}
x(1);
using static IronRuby.Ruby;
class Print1To100WithoutLoopsDemo
{
static void Main() =>
CreateEngine().Execute("(1..100).each {|i| System::Console.write_line i }");
}
Эй, почему бы и нет?
Нет петлей, без рекурсии, просто хэш-подобное массив функций для выбора того, как филиал:
using System;
using System.Collections.Generic;
namespace Juliet
{
class PrintStateMachine
{
int state;
int max;
Action<Action>[] actions;
public PrintStateMachine(int max)
{
this.state = 0;
this.max = max;
this.actions = new Action<Action>[] { IncrPrint, Stop };
}
void IncrPrint(Action next)
{
Console.WriteLine(++state);
next();
}
void Stop(Action next) { }
public void Start()
{
Action<Action> action = actions[Math.Sign(state - max) + 1];
action(Start);
}
}
class Program
{
static void Main(string[] args)
{
PrintStateMachine printer = new PrintStateMachine(100);
printer.Start();
Console.ReadLine();
}
}
}
Я думаю, что проблема Sergionni в два раза.
Во-первых, это правда, что так называемый корневой родственник, подобный Балюду, на самом деле домен относительно, поэтому в примере относительно http://example.com/
и не к http://example.com/context/
.
Итак, вы должны указать
<link rel="stylesheet" type="text/css" href="${request.contextPath}/styles/decoration.css" />
BTW Balusc, поздравления, это первый раз, когда я вижу, что это правильно объяснил! Я много боролся, чтобы обнаружить это.
Но, если вы хотите упростить и предложить:
<link rel="stylesheet" type="text/css" href="styles/decoration.css" />
Предполагая, что стиль DIR является Sibring вашей текущей страницы, то вы можете иметь вторую проблему:
Вы тогда в относительный метод URL и, Я пришел на эту страницу вперед, а не перенаправить, ваш браузер может быть одурачен и не сможет следовать относительном пути.
Чтобы решить эту вторую проблему, вы должны добавить это:
<head>
<base href="http://${request.serverName}:${request.serverPort}${request.contextPath}${request.servletPath}" />
Базовый элемент должен предшествовать любой ссылке.
Base Command вы сообщаете свой браузер, где вы на самом деле.
Надеюсь, это поможет.
и BTW Другая странная вещь в этом Wondeful World JSF:
, чтобы связаться с страницы на шаблон своей факте, корневой относительной ссылкой является, на этот раз, включая контекст, так как:
<ui:composition template="/layouts/layout.xhtml">
Эта ссылка на самом деле для http://example.com/context/layouts/layout.xhtml
и не к http://example.com/layouts/layout.xhtml
, как для
Или
.
Жан-Мари Галлиота
-121--2786233-Мое решение находится в потоке 2045637 , который задает тот же вопрос для Java.
полностью ненужный метод:
int i = 1;
System.Timers.Timer t = new System.Timers.Timer(1);
t.Elapsed += new ElapsedEventHandler(
(sender, e) => { if (i > 100) t.Enabled = false; else Console.WriteLine(i++); });
t.Enabled = true;
Thread.Sleep(110);
Просто LINQ это ...
Console.WriteLine(Enumerable.Range(1, 100)
.Select(s => s.ToString())
.Aggregate((x, y) => x + "," + y));
С Регулярные выражения
using System.Text.RegularExpressions;
public class Hello1
{
public static void Main()
{
// Count to 128 in unary
string numbers = "x\n";
numbers += Regex.Replace(numbers, "x+\n", "x$&");
numbers += Regex.Replace(numbers, "x+\n", "xx$&");
numbers += Regex.Replace(numbers, "x+\n", "xxxx$&");
numbers += Regex.Replace(numbers, "x+\n", "xxxxxxxx$&");
numbers += Regex.Replace(numbers, "x+\n", "xxxxxxxxxxxxxxxx$&");
numbers += Regex.Replace(numbers, "x+\n", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx$&");
numbers += Regex.Replace(numbers, "x+\n", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx$&");
// Out of 1..128, select 1..100
numbers = Regex.Match(numbers, "(.*\n){100}").Value;
// Convert from unary to decimal
numbers = Regex.Replace(numbers, "x{10}", "<10>");
numbers = Regex.Replace(numbers, "x{9}", "<9>");
numbers = Regex.Replace(numbers, "x{8}", "<8>");
numbers = Regex.Replace(numbers, "x{7}", "<7>");
numbers = Regex.Replace(numbers, "x{6}", "<6>");
numbers = Regex.Replace(numbers, "x{5}", "<5>");
numbers = Regex.Replace(numbers, "x{4}", "<4>");
numbers = Regex.Replace(numbers, "x{3}", "<3>");
numbers = Regex.Replace(numbers, "x{2}", "<2>");
numbers = Regex.Replace(numbers, "x{1}", "<1>");
numbers = Regex.Replace(numbers, "(<10>){10}", "<100>");
numbers = Regex.Replace(numbers, "(<10>){9}", "<90>");
numbers = Regex.Replace(numbers, "(<10>){8}", "<80>");
numbers = Regex.Replace(numbers, "(<10>){7}", "<70>");
numbers = Regex.Replace(numbers, "(<10>){6}", "<60>");
numbers = Regex.Replace(numbers, "(<10>){5}", "<50>");
numbers = Regex.Replace(numbers, "(<10>){4}", "<40>");
numbers = Regex.Replace(numbers, "(<10>){3}", "<30>");
numbers = Regex.Replace(numbers, "(<10>){2}", "<20>");
numbers = Regex.Replace(numbers, "(<[0-9]{3}>)$", "$1<00>");
numbers = Regex.Replace(numbers, "(<[0-9]{2}>)$", "$1<0>");
numbers = Regex.Replace(numbers, "<([0-9]0)>\n", "$1\n");
numbers = Regex.Replace(numbers, "<([0-9])0*>", "$1");
System.Console.WriteLine(numbers);
}
}
Выход:
# => 1
# => 2
# ...
# => 99
# => 100
Просто для уродливой буквальной интерпретации:
Console.WriteLine("numbers from 1 to 100 without using loops, ");
(вы можете смеяться сейчас или позже, или нет)