কোনও সি # ল্যাম্বডা ঘোষণা করার সাথে সাথেই এটি কল করার কোনও উপায় আছে কি?


29

ল্যাম্বডা ফাংশনটি ঘোষণা করা এবং তাত্ক্ষণিকভাবে এটি কল করা সম্ভব:

Func<int, int> lambda = (input) => { return 1; };
int output = lambda(0);

আমি ভাবছি এক লাইনে এটি করা সম্ভব কিনা, উদাহরণস্বরূপ কিছু

int output = (input) => { return 1; }(0);

যা একটি সংকলক ত্রুটি দেয় "পদ্ধতিটির নাম প্রত্যাশিত"। Castালাই Func<int, int>কাজ করাও কাজ করে না:

int output = (Func<int, int>)((input) => { return 1; })(0);

একই ত্রুটি দেয় এবং নীচে উল্লিখিত কারণগুলির জন্য আমি ইনপুট আর্গুমেন্টের ধরণ (প্রথমটি int) স্পষ্টভাবে উল্লেখ না করা এড়াতে চাই ।


আপনি সম্ভবত ভাবছেন যে আমি কোডটি সরাসরি এম্বেড করার পরিবর্তে কেন এটি করতে চাই int output = 1;। কারণটি নিম্নরূপ: আমি একটি এসওএপি ওয়েবসার্চিসহ একটি রেফারেন্স তৈরি করেছি svcutil, যা নেস্টেড উপাদানগুলির কারণে অত্যন্ত দীর্ঘ শ্রেণীর নাম উত্পন্ন করে, যা আমি টাইপ করতে এড়াতে চাই। পরিবর্তে তাই

var o = await client.GetOrderAsync(request);
return new Order {
    OrderDate = o.OrderDate,
    ...
    Shipments = o.Shipment_Order == null ? new Shipment[0]
        o.Shipment_Order.Select(sh => new Shipment {
            ShipmentID = sh.ShipmentID,
            ...
            Address = CreateAddress(sh.ReceiverAddress_Shipment);
        }).ToArray()
};

এবং একটি পৃথক CreateAddress(GetOrderResultOrderShipment_OrderShipmentShipment_Address address)পদ্ধতি (আসল নামগুলি আরও দীর্ঘ, এবং ফর্মটি সম্পর্কে আমার খুব সীমিত নিয়ন্ত্রণ আছে), আমি লিখতে চাই

var o = await client.GetOrderAsync(request);
return new Order {
    OrderDate = o.OrderDate,
    ...
    Shipments = o.Shipment_Order == null ? new Shipment[0]
        o.Shipment_Order.Select(sh => new Shipment {
            ShipmentID = sh.ShipmentID,
            ...
            Address = sh.ReceiverAddress_Shipment == null ? null : () => {
                var a = sh.ReceiverAddress_Shipment.Address;
                return new Address {
                    Street = a.Street
                    ...
                };
            }()
        }).ToArray()
};

আমি জানি আমি লিখতে পারি

Address = sh.ReceiverAddress_Shipment == null ? null : new Address {
    Street = sh.ReceiverAddress_Shipment.Address.Street,
    ...
}

এমনকি sh.ReceiverAddress_Shipment.Addressযদি অনেক ক্ষেত্র থাকে তবে তা ( অংশ) খুব পুনরাবৃত্ত হয়। ল্যাম্বডা ঘোষণা করা এবং ততক্ষণে এটি কল করা আরও মার্জিত কম অক্ষর লিখতে হবে।


int output = ((Func<int>) (() => { return 1; }))();
দিমিত্রি বাইচেনকো

কেন কেবল একটি ছোট মোড়ক লিখবেন না: public T Exec<T>(Func<T> func) => return func();এবং এটির মতো ব্যবহার করুন: এটি int x = Exec(() => { return 1; });আমার সমস্ত প্যারেন্স সহ কাস্টিংয়ের চেয়ে অনেক ভাল পড়ে reads
জার্মানি

@germi সুন্দর ধারণা, তবে এটি আমাকে দেয় "এক্সিকিউট পদ্ধতিটির জন্য প্রকারের আর্গুমেন্টগুলি ব্যবহার থেকে অনুমান করা যায় না।"
গ্লোরিফাইন্ডেল

@ গ্লোরফাইন্ডেল আপনি কিছু ভুল করেছেন, তারপরে: ডটনেটফিডেল.ট.
োকু e

@ ক্যান্টন 7 কারণ আমি আসলে ইনপুট প্যারামিটার সহ একটি ল্যাম্বডা ব্যবহার করছি ... ধন্যবাদ, এটি এখন কাজ করে।
গ্লোরিফাইন্ডেল

উত্তর:


29

ল্যাম্বডাকে কাস্ট করার চেষ্টা করার পরিবর্তে, আমি আপনাকে একটি ছোট সহায়ক ফাংশন ব্যবহার করার প্রস্তাব দিচ্ছি:

public static TOut Exec<TIn, TOut>(Func<TIn, TOut> func, TIn input) => func(input);

যা আপনি পরে এই মত ব্যবহার করতে পারে: int x = Exec(myVar => myVar + 2, 0);। এখানে প্রস্তাবিত বিকল্পগুলির চেয়ে এটি আমার কাছে খুব সুন্দর পড়ে।


25

এটি কুৎসিত, তবে এটি সম্ভব:

int output = ((Func<int, int>)(input => { return 1; }))(0);

আপনি কাস্ট করতে পারেন, তবে ল্যাম্বডাটি বন্ধনীতে আবদ্ধ হওয়া দরকার।

উপরেরগুলি পাশাপাশি সরল করা যেতে পারে:

int output = ((Func<int, int>)(input => 1))(0);

2
আহ, অবশ্যই আমি কেবল চেষ্টা করেছিলাম int output = (Func<int>)(() => { return 1; })();তবে লাম্বদা কার্যকর করার চেয়ে কাস্টের কম অগ্রাধিকার রয়েছে।
গ্লোরিফাইন্ডেল

যদিও এটি অত্যন্ত দীর্ঘ শ্রেণীর নাম লিখতে না চাওয়ার সমস্যাটি এখনও সমাধান করে না।
গ্লোরফাইন্ডেল

4

সি # তে লাম্বদা আক্ষরিকর মধ্যে একটি কৌতূহলপূর্ণ পার্থক্য রয়েছে যে তাদের অর্থটি তাদের ধরণের উপর নির্ভরশীল। এগুলি মূলত তাদের রিটার্নের ধরণের উপর অতিরিক্ত লোড হয় যা এমন কিছু যা সি # তে অন্য কোথাও নেই। (সংখ্যাসূচক আক্ষরিক কিছুটা মিল রয়েছে))

সঠিক একই ল্যামডা আক্ষরিক করতে পারেন একটি বেনামী ফাংশন যে আপনি নির্বাহ করতে পারেন (যেমন একটি মূল্যায়ন Func/ Action) বা ধরনের একটি বিমূর্ত সিনট্যাক্স বৃক্ষ মত (যেমন একটি LINQ এক্সপ্রেশন বৃক্ষ), শরীরের ভিতরে অপারেশনের একটি বিমূর্ত উপস্থাপনা।

দ্বিতীয়টি উদাহরণস্বরূপ, লিনকু থেকে এসকিউএল, লিনকিউ থেকে এক্সএমএল ইত্যাদি কীভাবে কাজ করে: ল্যাম্বডাস এক্সিকিউটেবল কোডে মূল্যায়ন করেন না , তারা লিনকিউ এক্সপ্রেশন ট্রিগুলিতে মূল্যায়ন করেন এবং লিনকিউ সরবরাহকারী তখন এই এক্সপ্রেশন ট্রিগুলি কী বুঝতে পারে তা বুঝতে ল্যাম্বডা এর বডিটি করছে এবং এটি থেকে একটি এসকিউএল কোয়েরি তৈরি করে।

আপনার ক্ষেত্রে, কম্পাইলারটি জানার কোনও উপায় নেই যে ল্যাম্বডা আক্ষরিক কোথায় Funcবা লিনকিউ এক্সপ্রেশনকে মূল্যায়ন করার কথা । এটা কেন হয় Johnathan বার্কলে এর উত্তর কাজ করে: এটা ল্যামডা এক্সপ্রেশন একটি টাইপ দেয় এবং তাই কম্পাইলার জানে যে যদি আপনি চান একটি Funcকম্পাইল করা কোডটি দিয়ে executes একটি অ-মূল্যায়ন LINQ এক্সপ্রেশন বৃক্ষ পরিবর্তে আপনার ল্যামডা লাশ যে প্রতিনিধিত্ব করে কোড ভিতরে ল্যাম্বডা শরীর।


3

আপনি ঘোষণা ইনলাইন পারে Funcকরে

int output = (new Func<int, int>(() => { return 1; }))(0);

এবং অবিলম্বে এটি অনুরোধ।


2

আপনি Selectপদ্ধতিতেও উপন্যাসটি তৈরি করতে পারেন

var o = await client.GetOrderAsync(request);
return new Order {
    OrderDate = o.OrderDate,
    ...
    Shipments = o.Shipment_Order == null ? new Shipment[0]
        o.Shipment_Order.Select(sh => {
          var s = sh.ReceiverAddress_Shipment;
          var a = s.Address;
          return new Shipment {
            ShipmentID = sh.ShipmentID,
            ...
            Address = s == null ? 
                      null : 
                      new Address {
                        Street = a.Street
                        ...
                      }
          };
        }).ToArray()
};

বা ??অপারেটরের সাথে

var o = await client.GetOrderAsync(request);
return new Order {
    OrderDate = o.OrderDate,
    ...
    Shipments = o.Shipment_Order?.Select(sh => {
        var s = sh.ReceiverAddress_Shipment;
        var a = s.Address;
        return new Shipment {
            ShipmentID = sh.ShipmentID,
            ...
            Address = s == null ? 
                      null : 
                      new Address {
                          Street = a.Street
                          ...
                      }
        };
    }).ToArray() ?? new Shipment[0]
};

1

আপনি যদি কিছু এক্সটেনশন পদ্ধতি ডিজাইন নির্দেশিকাগুলি লঙ্ঘন করতে আপত্তি না করেন তবে নাল-শর্তসাপেক্ষ অপারেটরের সাথে মিলিত এক্সটেনশন পদ্ধতিগুলি ?.আপনাকে যুক্তিসঙ্গতভাবে অনেক দূর নিয়ে যেতে পারে:

public static class Extensions
{
    public static TOut Map<TIn, TOut>(this TIn value, Func<TIn, TOut> map)
        where TIn : class
        => value == null ? default(TOut) : map(value);

    public static IEnumerable<T> OrEmpty<T>(this IEnumerable<T> items)
        => items ?? Enumerable.Empty<T>();
}

এটি আপনাকে দেবে:

return new Order
{
    OrderDate = o.OrderDate,
    Shipments = o.Shipment_Order.OrEmpty().Select(sh => new Shipment
    {
        ShipmentID = sh.ShipmentID,
        Address = sh.ReceiverAddress_Shipment?.Address.Map(a => new Address
        {
            Street = a.Street
        })
    }).ToArray()
};

এবং যদি আপনার বেশিরভাগ অ্যারে প্রয়োজন হয়, তবে ToArrayআরও কয়েকটি পদ্ধতি কলকে আবশ্যক করে এক্সটেনশন পদ্ধতিটি ওভাররাইড করুন :

public static TOut[] ToArray<TIn, TOut>(this IEnumerable<TIn> items, Func<TIn, TOut> map)
    => items == null ? new TOut[0] : items.Select(map).ToArray();

ফলাফল:

return new Order
{
    OrderDate = o.OrderDate,
    Shipments = o.Shipment_Order.ToArray(sh => new Shipment
    {
        ShipmentID = sh.ShipmentID,
        Address = sh.ReceiverAddress_Shipment?.Address.Map(a => new Address
        {
            Street = a.Street
        })
    })
};
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.