Действительно ли возможно заставить параметр реализовать два интерфейса?

Вы можете передавать данные в ответ, но вы не можете динамически обновлять шаблон так, как вы описываете. Шаблон создается один раз на стороне сервера, а затем отправляется клиенту. Вам нужно будет использовать JavaScript для чтения потокового ответа и вывода данных на стороне клиента.

Используйте XMLHttpRequest, чтобы сделать запрос к конечной точке, которая будет передавать данные. Затем периодически читайте поток, пока он не будет выполнен.

В этом примере используется очень простой формат сообщения: одна строка данных, за которой следует новая строка. Конечно, вы можете так же усложниться в разборе, сколько хотите, пока есть способ идентифицировать каждое сообщение. Например, вы можете вернуть объект JSON и декодировать его на клиенте.

from time import sleep
from flask import Flask, render_template
from math import sqrt

app = Flask(__name__)

@app.route('/')
def index():
    # render the template (below) that will use JavaScript to read the stream
    return render_template('index.html')

@app.route('/stream_sqrt')
def stream():
    def generate():
        for i in range(500):
            yield '{}\n'.format(sqrt(i))
            sleep(1)

    return app.response_class(generate(), mimetype='text/plain')

app.run()
<p>This is the latest output: <span id="latest"></span></p>
<p>This is all the output:</p>
<ul id="output"></ul>
<script>
    var latest = document.getElementById('latest');
    var output = document.getElementById('output');

    var xhr = new XMLHttpRequest();
    xhr.open('GET', '{{ url_for('stream') }}');
    xhr.send();
    var position = 0;

    function handleNewData() {
        // the response text include the entire response so far
        // split the messages, then take the messages that haven't been handled yet
        // position tracks how many messages have been handled
        // messages end with a newline, so split will always show one extra empty message at the end
        var messages = xhr.responseText.split('\n');
        messages.slice(position, -1).forEach(function(value) {
            latest.textContent = value;  // update the latest value in place
            // build and append a new item to a list to log all output
            var item = document.createElement('li');
            item.textContent = value;
            output.appendChild(item);
        });
        position = messages.length - 1;
    }

    var timer;
    timer = setInterval(function() {
        // check the response for new data
        handleNewData();
        // stop checking once the response has ended
        if (xhr.readyState == XMLHttpRequest.DONE) {
            clearInterval(timer);
            latest.textContent = 'Done';
        }
    }, 1000);
</script>
23
задан Pondidum 21 April 2009 в 10:59
поделиться

4 ответа

Вы можете:

1) Определить интерфейс, который наследует оба требуемых интерфейса:

public interface ICombinedInterface : IComparable, ICollection {... }

private void DoSomething(ICombinedInterface input) {... }

2) Использовать обобщенные значения:

private void DoSomething<T>(T input)
    where T : IComparable, ICollection
{...}
54
ответ дан 29 November 2019 в 01:08
поделиться

Упомянутый выше подход универсальной функции является хорошим, с одним большим предостережением: для того, чтобы типизировать объект так, чтобы он мог быть передан в подпрограмму с несколькими общими ограничениями, необходимо знать тип, который удовлетворяет этим ограничениям и является родительский тип объекта приведения. Подпрограмма, которая принимает такой объект, будет знать такой тип (он был передан как параметр универсального типа), но у класса нет хорошего способа сохранить эту информацию и использовать ее позже. Если различные несвязанные типы реализуют как IFoo, так и IBar, было бы трудно спроектировать подпрограмму, которая могла бы принимать несколько не связанных экземпляров объекта, сохранять их в списке или чем-то еще, а затем передавать все элементы в списке подпрограмме. с общим параметром IFoo + IBar.

Если такой сценарий может потребоваться, наилучшим подходом будет иметь неуниверсальный аналог для каждой общей процедуры, который бы принимал, например, параметр типа IFoo и приведите его к IBar по мере необходимости. Затем можно сохранить все элементы в списке < IFoo > и передать их рутине. Можно было бы потерять безопасность типов универсального метода, но иногда идеальная безопасность типов не достижима.

1
ответ дан supercat 29 November 2019 в 01:08
поделиться

Вы можете унаследовать другой интерфейс от этих двух интерфейсов и заставить ваш параметр реализовать этот интерфейс.

5
ответ дан 29 November 2019 в 01:08
поделиться

Ну, да, и нет.

Вы можете, как предложил Стив, создать еще один, третий, интерфейс, который происходит от двух, которые вы хотите, и использовать его для типа параметра.

Однако это также потребует, чтобы используемый класс реализовывал и этот третий интерфейс.

Другими словами, это не сработает:

public interface I1 { }
public interface I2 { }
public class C : I1, I2 { }

public interface I3 : I1, I2 { }
public class YourClass
{
    public void Test(I3 i) { }
}

...
YourClass yc = new YourClass();
C c = new C();
yc.Test(c); // won't work, C does not implement I3

Однако вы можете обмануть компилятор так, как вам нужно. хочу через дженерики.

public class YourClass
{
    public void Test<T>(T i) where T: I1, I2 { }
}

Теперь это будет работать. Я все еще не уверен на 100%, что это не вызовет у вас других проблем, но я должен подумать об этом.

2
ответ дан 29 November 2019 в 01:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: