Как разница между методом Response.Redirect и Server.Transfer?

2 коментари(и/ев)

Microsoft .NET Framework: Как разница между методом Response.Redirect и Server.Transfer?Вызывая метод Response.Redirect, сервер отсылает клиентскому браузеру HTTP header со статус-кодом (302), который означает, что обьект был перемещён. Так же в заголовке указывается новое место обьекта. Смотрим, что получается после вызова Response.Redirect("~/Default.aspx"):

 

[code=xml]
HTTP/1.1 302 Found
Server: ASP.NET Development Server/9.0.0.0
Date: Thu, 04 Sep 2008 11:59:21 GMT
X-AspNet-Version: 2.0.50727
Location: /Default.aspx
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 130
Connection: Close

<html><head><title>Object moved</title></head><body>
<h2>Object moved to <a href="/Default.aspx">here</a>.</h2>
</body></html>
[/code]
Если клиентский браузер нормально воспринимает перенаправления, то такой страницы вы не увидите. Браузер автоматически запросит ресурс по указанном Location.

На заметку

1. В том случае, когда первоначальный запрос был вызван POST-методом, после перенаправления методом Response.Redirect на другую страницу теряются все данные формы.
2. Благодаря же тому, что браузер посылает второй запрос, его возможно перенаправить на внешний ресурс.

Теперь пару слов о Server.Transfer. В отличии от Response.Redirect данный метод перенаправляет выполнение с одной страницы на другую на сервере. Это хорошо проявляется,  если посмотреть на Url, после перенаправления. Он такой же как и в первом запросе. Более подробно на примере:
Браузер запрашивает страницу http://localhost:4107/Default.aspx. Метод Page_Load страницы выглядит так [code=csharp]protected void Page_Load(object sender, EventArgs e)
{
     Server.Transfer("~/Foo.aspx");
} [/code]
Смотрим на Url, он остался таким же (http://localhost:4107/Default.aspx), но в браузере отображена страница Foo.aspx.
Ещё одним замечальным свойством Server.Transfer является то, что он позволяет передавать второй странице данные формы и строки запроса первой. Если же такие данные на второй странице не нужны, можно почистить их передав вторым параметром false. Пример: [code=csharp]
Server.Transfer("~/Foo.aspx", false); [/code]
На заметку
1. Если первая страница записывает что-то в буфер ответа (Response), то перед вызовом Server.Transfer Response нужно почистить, иначе получится каша: содержимое второй страницы добавится после содержимого первой страницы.
2. Так Server.Transfer выполняется на сервере, невозможно перенаправить запрос на внешний сайт.

Как разница между методом Finalize и деструктором в C#?

Комментарии отсутствуют

Microsoft .NET Framework: Как разница между методом Finalize и деструктором? Как известно, в C# не нужно заботиться об освобождении памяти, так как это приходится делать в том же С++, ведь всю рутинную работу по управлению памятью перебрал на себя GC. Но всё же иногда класс должен сам заботиться об "уборке", это касается тех случаев, когда он использует неуправляемые ресурсы (прямой доступ к дескрипторам файлов ОС, соединение с базой данных). Метод Finalize, что наследуется от класса Object как раз и предназначен для освобождения неуправляемых ресурсов. Данный метод вызывается GC на этапе освобождения памяти, занимаемой обьектом. Всё казалось бы просто: переопределяем метод Finalize в дочернем классе, реализовываем логику освобождения ресурсов и всё.... Но не тут то было. И хотя в базовом класе он обьявлен следующим образом:
[code=csharp]public class Object
{
    //.....
    protected virtual void Finalize()
    {
    
    }
}
[/code]
Написать что-то вроде
[code=csharp]//Помним, что все классы неявно наследуются от Object
public class First
{
    protected override void Finalize(){}
}
[/code]
увы, нет возможности. Компилятор выдаст ошибку
Do not override object.Finalize. Instead, provide a destructor.

В этом сообщении и кроется подсказка. Явно переопределить метод Finalize нельзя, нужно вместо него использовать деструктор. Синтаксис деструктора в C# похож на синтаксис в С++. Пример:
[code=csharp]class First
{
    ~First()
    {
        Console.WriteLine("First destructor was called");
    }
}
[/code]
А теперь попробуем дизасемблировать этот код с помощью IlDasm. Смотрим результат:
[code=csharp].method family hidebysig virtual instance void
        Finalize() cil managed
{
  // Code size       25 (0x19)
  .maxstack  1
  .try
  {
    IL_0000:  nop
    IL_0001:  ldstr      "First destructor was called"
    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000b:  nop
    IL_000c:  nop
    IL_000d:  leave.s    IL_0017
  }  // end .try
  finally
  {
    IL_000f:  ldarg.0
    IL_0010:  call       instance void [mscorlib]System.Object::Finalize()
    IL_0015:  nop
    IL_0016:  endfinally
  }  // end handler
  IL_0017:  nop
  IL_0018:  ret
} // end of method First::Finalize
[/code]
Что же получилось?! В результате компиляции деструктор преобразовался в метод Finalize. Метод Finalize содержит тело деструктора в блоке try, за которым следует блок finally, где вызывается метод Finalize базоваго класса. С выше сказанного можна сделать вывод, что в C# метод Finalize и деструктор - это одно и тоже.

Что нужно помнить:

1. Деструкторы вызываюся автоматически, их не нужно вызываять явно.
2. Деструкторы не могу быть перегружены, как следствие, каждый класс может иметь ноль или один деструктор.
3. Деструкторы могут быть только у классов.
4. Деструкторы не наследуются.
5. Вызов деструктора может произойти в любой момент после того как обьект был помечен на удаление.
6. Когда обьект удаляется, деструкторы вызываюся в порядке от дочернего к родительскому.