255
Передача.параметров.в.метод.по.ссылке
if (fs != null) fs.Close(); // Закрыть последний обрабатываемый файл
// Открыть следующий файл или вернуть null, если файлов больше нет
if (noMoreFilesToProcess) fs = null;
else fs = new FileStream (...);
}
}
Еще один пример, демонстрирующий использование ключевого слова
ref
для
реализации метода, меняющего местами два ссылочных типа:
public static void Swap(ref Object a, ref Object b) {
Object t = b;
b = a;
a = t;
}
Кажется, что код, меняющий местами ссылки на два объекта типа
String
, дол-
жен выглядеть так:
public static void SomeMethod() {
String s1 = "Jeffrey";
String s2 = "Richter";
Swap(ref s1, ref s2);
Console.WriteLine(s1); // Выводит "Richter"
Console.WriteLine(s2); // Выводит "Jeffrey"
}
Однако компилироваться этот код не будет:
ведь переменные, передаваемые
методу по ссылке, должны быть одного типа, объявленного в сигнатуре метода.
Иначе говоря, метод
Swap
ожидает получить ссылки на тип
Object
, а
не на тип
String
. Решение же нашей задачи выглядит следующим образом:
public static void SomeMethod() {
String s1 = "Jeffrey";
String s2 = "Richter";
// Тип передаваемых по ссылке переменных должен
// соответствовать ожидаемому
Object o1 = s1, o2 = s2;
Swap(ref o1, ref o2);
// Приведение объектов к строковому типу
s1 = (String) o1;
s2 = (String) o2;
Console.WriteLine(s1); // Выводит "Richter"
Console.WriteLine(s2); // Выводит "Jeffrey"
}
Такая версия метода
SomeMethod
будет компилироваться и работать нужным
нам образом. Причиной ограничения, которое нам пришлось обходить,
является
256
Глава.9 .Параметры
обеспечение безопасности типов. Вот пример кода, нарушающего безопасность
типов (к счастью, он не компилируется):
internal sealed class SomeType {
public Int32 m_val;
}
public sealed class Program {
public static void Main() {
SomeType st;
// Следующая строка выдает ошибку CS1503: Argument '1':
// cannot convert from 'ref SomeType' to 'ref object'.
GetAnObject(out st);
Console.WriteLine(st.m_val);
}
private static void GetAnObject(out Object o) {
o = new String('X', 100);
}
}
Совершенно ясно, что здесь метод
Main
ожидает от метода
GetAnObject
объект
SomeType
. Однако поскольку в сигнатуре
GetAnObject
задана ссылка на
Object
,
метод
GetAnObject
может инициализировать параметр
o
объектом произвольного
типа. В
этом примере параметр
st
в момент, когда метод
GetAnObject
возвращает
управление методу
Main
, ссылается на объект типа
String
, в то время как ожида-
ется тип
SomeType
.
Соответственно, вызов метода
Console.WriteLine
закончится
неудачей. Впрочем, компилятор C# откажется компилировать этот код, так как
st
представляет собой ссылку на объект типа
SomeType
,
тогда как метод
GetAnObject
требует ссылку на
Object
.
Однако, как оказалось, эти методы можно заставить работать при помощи обоб-
щений. Вот так следует исправить показанный ранее метод
Swap
:
public static void Swap
(ref T a, ref T b) {
T t = b;
b = a;
a = t;
}
После этого следующий код (идентичный ранее показанному) будет без проблем
компилироваться и выполняться:
public static void SomeMethod() {
String s1 = "Jeffrey";
String s2 = "Richter";
Swap(ref s1, ref s2);
Console.WriteLine(s1); // Выводит "Richter"
Console.WriteLine(s2); // Выводит "Jeffrey"
}
257
Передача.переменного.количества.аргументов
За другими примерами решения, использующими обобщения, обращайтесь к
классу
System.Threading.Interlocked
с его методами
CompareExchange
и
Exchange
.
Do'stlaringiz bilan baham: