Конечно, есть много таких подходов, как синхронный запрос, обещание, но из моего опыта я думаю, что вы должны использовать подход обратного вызова. Естественно, что асинхронное поведение Javascript. Итак, ваш фрагмент кода можно переписать немного иначе:
function foo() {
var result;
$.ajax({
url: '...',
success: function(response) {
myCallback(response);
}
});
return result;
}
function myCallback(response) {
// Does something.
}
=============
UPDATE: я использовал этот ответ в качестве основы для этой записи в блоге:
Почему ref и параметры не позволяют изменять тип?
См. страницу блога для получения дополнительных комментариев по этой проблеме. Спасибо за отличный вопрос.
=============
Предположим, что у вас есть классы Animal
, Mammal
, Reptile
, Giraffe
, Turtle
и Tiger
, с очевидными отношениями подкласса.
Теперь предположим, что у вас есть метод void M(ref Mammal m)
. M
может читать и записывать m
.
Можете ли вы передать переменную типа
blockquote>Animal
наM
?№. Эта переменная может содержать
Turtle
, ноM
предполагает, что она содержит только млекопитающих.Turtle
не являетсяMammal
.Заключение 1: параметры
ref
не могут быть сделаны «большими». (Есть больше животных, чем млекопитающих, поэтому переменная становится «больше», потому что она может содержать больше вещей.)
Можете ли вы передать переменную типа
blockquote>Giraffe
наM
?№.
M
может записать наm
, аM
может захотеть записатьTiger
вm
. Теперь вы поместилиTiger
в переменную, которая фактически имеет типGiraffe
.Вывод 2:
ref
параметры не могут быть сделаны «меньше».
Теперь рассмотрим
N(out Mammal n)
.Можете ли вы передать переменную типа
blockquote>Giraffe
наN
?№.
N
может писать вn
, аN
может захотеть записатьTiger
.Заключение 3:
out
параметры не могут быть сделаны «меньше».
Можете ли вы передать переменную типа
blockquote>Animal
наN
?Хмм.
Ну, почему бы и нет?
N
не может читать изn
, он может писать только ему, не так ли? Вы записываетеTiger
в переменную типаAnimal
, и все вы настроены, верно?Неверно. Правило не "
N
может писать толькоn
".Правила кратко:
1)
N
должен записать вn
, прежде чемN
вернется нормально. (ЕслиN
выбрасывает, все ставки отключены.)2)
N
должен что-то записать вn
, прежде чем он что-то прочитает изn
.разрешает эту последовательность событий:
- Объявить поле
x
типаAnimal
.- Пропустить
x
как параметрout
доN
.N
записываетTiger
вn
, который является псевдонимом дляx
.- В другом потоке кто-то пишет
Turtle
вx
.N
пытается прочитать содержимоеn
и обнаруживаетTurtle
в том, что, по его мнению, является переменной типаMammal
.Очевидно, мы хотим сделать это незаконным.
Заключение 4:
out
параметры не могут быть сделаны «большими».
Окончательное заключение : Ни параметры
ref
, ниout
могут варьироваться в зависимости от их типа. Иначе говоря, нужно разбить безопасную безопасность типа.Если эти вопросы в теории базового типа вас интересуют, подумайте о том, чтобы прочитать мою серию о том, как ковариация и контравариантность работают в C # 4.0 .
Вы боретесь с классической проблемой ковариации (и контравариантности) ООП, см. wikipedia : многое, поскольку этот факт может игнорировать интуитивные ожидания, математически невозможно разрешить замену производных классов вместо базовые для изменяемых (назначаемых) аргументов (а также контейнеров, чьи позиции можно присваивать по той же причине), все еще соблюдая принцип Лискова . Почему это так набросано в существующих ответах и более подробно изучается в этих статьях и ссылках на них.
Языки ООП, которые, как представляется, делают это, оставаясь традиционно статически типичными, «обманывают» (вставляя скрытую динамику проверять тип, или требовать проверки всех источников во время компиляции); фундаментальный выбор: либо отказаться от этой ковариации и принять недоумение практикующих (как это делает C # здесь), либо перейти к подходу с динамической типизацией (как к самому первому языку ООП, Smalltalk), или перейти к неизменяемому (однострочному) задание), как и функциональные языки (по неизменности, вы можете поддерживать ковариацию, а также избегать других связанных головоломок, таких как тот факт, что вы не можете иметь прямоугольный подкласс Rectangle в мире изменяемых данных).
В то время как другие ответы кратко объясняли причины такого поведения, я думаю, стоит упомянуть, что если вам действительно нужно что-то сделать такого рода, вы можете выполнить аналогичную функциональность, сделав Foo2 в общий метод, например:
class A {}
class B : A {}
class C
{
C()
{
var b = new B();
Foo(b);
Foo2(ref b); // <= no compile error!
}
void Foo(A a) {}
void Foo2<AType> (ref AType a) where AType: A {}
}
Поскольку предоставление Foo2
a ref B
приведет к некорректному объекту, потому что Foo2
знает, как заполнить A
часть B
.
Разве это не то, что компилятор говорит вам, что вы хотите, чтобы я явно бросил объект, чтобы он мог быть уверен, что вы знаете, каковы ваши намерения?
Foo2(ref (A)b)
Рассмотрим:
class C : A {}
class B : A {}
void Foo2(ref A a) { a = new C(); }
B b = null;
Foo2(ref b);
Это нарушит безопасность типа
Если вы используете практические примеры для ваших типов, вы увидите следующее:
SqlConnection connection = new SqlConnection();
Foo(ref connection);
И теперь у вас есть ваша функция, которая принимает предка ( ie Object
):
void Foo2(ref Object connection) { }
Что может быть с этим связано?
void Foo2(ref Object connection)
{
connection = new Bitmap();
}
Вам просто удалось назначить Bitmap
на ваш SqlConnection
.
Это нехорошо.
Повторите попытку с другими:
SqlConnection conn = new SqlConnection();
Foo2(ref conn);
void Foo2(ref DbConnection connection)
{
conn = new OracleConnection();
}
Вы наполнили OracleConnection
поверх вашего SqlConnection
.
Поскольку в обоих случаях вы должны иметь возможность присвоить значение параметру ref / out.
Если вы попытаетесь передать b в метод Foo2 в качестве ссылки, а в Foo2 вы попытаетесь определить a = new A (), это будет недействительным. По той же причине, которую вы не можете написать:
B b = new A();
Имеет смысл с точки зрения безопасности, но я предпочел бы, чтобы компилятор выдал предупреждение вместо ошибки, поскольку существует законное использование полиморфных объектов, переданных по ссылке. например,
class Derp : interfaceX
{
int somevalue=0; //specified that this class contains somevalue by interfaceX
public Derp(int val)
{
somevalue = val;
}
}
void Foo(ref object obj){
int result = (interfaceX)obj.somevalue;
//do stuff to result variable... in my case data access
obj = Activator.CreateInstance(obj.GetType(), result);
}
main()
{
Derp x = new Derp();
Foo(ref Derp);
}
Это не будет компилироваться, но будет ли оно работать?
В моем случае моя функция приняла объект, и я не мог отправить ничего, поэтому я просто сделал
object bla = myVar;
Foo(ref bla);
И это работает
My Foo находится в VB.NET и он проверяет тип внутри и делает много логики
Прошу прощения, если мой ответ повторяется, но другие слишком длинны