سؤال

كيف يمكنني تنفيذ آلية التنفيذ المؤجلة الخاصة بي في C#؟

لذلك على سبيل المثال لدي:

string x = DoFoo();

هل من الممكن إجراء بعض السحر حتى لا يتم تنفيذ DoFoo حتى "أستخدم" x؟

هل كانت مفيدة؟

المحلول

ويمكنك استخدام lambdas / المندوبين:

Func<string> doit = () => DoFoo();
//  - or -
Func<string> doit = DoFoo;

وبعد ذلك يمكنك استدعاء doit تماما مثل الطريقة:

string x = doit();

وأعتقد أن الأقرب يمكنك الحصول على شيء من هذا القبيل:

Lazy<string> x = DoFoo;

string y = x; // "use" x

ومع تعريف Lazy<T> مشابهة لهذه (غير مجربة):

public class Lazy<T>
{
    private readonly Func<T> func;
    private bool hasValue;
    private T value;

    public Lazy(Func<T> func)
    {
        this.func = func;
        this.hasValue = false;
    }

    public static implicit operator Lazy<T>(Func<T> func)
    {
        return new Lazy<T>(func);
    }

    public static implicit operator T(Lazy<T> lazy)
    {
        if (!lazy.hasValue)
        {
            lazy.value = lazy.func();
            lazy.hasValue = true;
        }
        return lazy.value;
    }
}

ولسوء الحظ، يبدو أن الخوارزميات نوع الاستدلال على البرمجي لا يمكن لصناعة السيارات في الاستدلال نوع من Func<T> وهكذا لا يمكن أن المباراة إلى المشغل التحويل الضمني. نحن بحاجة إلى إعلان صريح نوع المندوب، مما يجعل البيانات المهمة أكثر مطول:

// none of these will compile...
Lazy<string> x = DoFoo;
Lazy<string> y = () => DoFoo();
Lazy<string> z = delegate() { return DoFoo(); };

// these all work...
Lazy<string> a = (Func<string>)DoFoo;
Lazy<string> b = (Func<string>)(() => DoFoo());
Lazy<string> c = new Func<string>(DoFoo);
Lazy<string> d = new Func<string>(() => DoFoo());
Lazy<string> e = new Lazy<string>(DoFoo);
Lazy<string> f = new Lazy<string>(() => DoFoo);

نصائح أخرى

أحد الخيارات هو استخدام Lazy<T> فئة، كانت في السابق من مكتبة الملحقات الموازية، وهي الآن جزء من .Net Framework 4.0.

يسمح لك بتأخير بيانات العملية بطريقة مدروسة.

وحين انها قذرة إلى حد ما يمكنك دائما استخدام الكلمة العائد:

public IEnumerable<int> DoFoo() {
   Console.WriteLine("doing foo");
   yield return 10;
}

[Test]
public void TestMethod()
{
    var x = DoFoo();
    Console.WriteLine("foo aquired?");
    Console.WriteLine(x.First());
}

وبدلا من تمرير سلسلة على س ، أو تمرير مندوب أن يشتري لك سلسلة

Func<String> fooFunc=()=>DoFoo();

لماذا لا فقط لا نسميه "DoFoo () 'حتى تريد؟

و- تحرير

وأعني، ماذا تعني "استخدام"

وعلى سبيل المثال، إذا كنت تريد أن يتم استدعاؤها عند '.ToString ()' ودعا، يمكنك دائما ترث الطبقة وتنفيذ وظيفة الخاص بك هناك (ولكن هذا سيكون IMHO unintuitive جدا).

وأنت تصف حد كبير LINQ في العمل. يصف استعلام LINQ كيفية الحصول على البيانات، ولكن يتم استرداد البيانات (يسمى DoFunc) فقط عندما يتم كرر الاستعلام. النظر في ما اذا كان يمكنك تغيير التصميم الخاص بك لقبول IQueryable<string> حيث كنت في حاجة الى string.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top