পরামিতি হিসাবে বেনামে কীভাবে পাস করবেন?


143

আমি অন্যান্য ফাংশনে প্যারামিটার হিসাবে বেনামে প্রকারগুলি কীভাবে পাস করতে পারি? এই উদাহরণ বিবেচনা করুন:

var query = from employee in employees select new { Name = employee.Name, Id = employee.Id };
LogEmployees(query);

এখানে ভেরিয়েবলের queryশক্ত প্রকার নেই। আমি আমার LogEmployeesফাংশনটি এটি গ্রহণ করার জন্য কীভাবে সংজ্ঞায়িত করব ?

public void LogEmployees (? list)
{
    foreach (? item in list)
    {

    }
}

অন্য কথায়, ?চিহ্নগুলির পরিবর্তে আমার কী ব্যবহার করা উচিত ।


1
ডেটা ফেরত দেওয়ার পরিবর্তে প্যারামিটারগুলি উত্তোলনের
রব চার্চ

উত্তর:


183

আমি মনে করি আপনার এই বেনামি ধরণের জন্য একটি ক্লাস করা উচিত। আমার মতে এটি করা সবচেয়ে বুদ্ধিমান কাজ হবে। তবে আপনি যদি সত্যিই না চান তবে আপনি গতিবিদ্যা ব্যবহার করতে পারেন:

public void LogEmployees (IEnumerable<dynamic> list)
{
    foreach (dynamic item in list)
    {
        string name = item.Name;
        int id = item.Id;
    }
}

নোট যে এই হয় না শক্তিশালী ভাবে টাইপ, তাই যদি, উদাহরণস্বরূপ, নাম EmployeeName পরিবর্তন, আপনি সেখানে রানটাইম পর্যন্ত একটা সমস্যা জানি না হবে।


আমি dynamicব্যবহারের কারণে এটি সঠিক উত্তর হিসাবে পরীক্ষা করেছি । আমি আসল আমার জন্য সুবিধাজনক। ধন্যবাদ :)
সা Saeedদ নেমতি

1
আমি একমত যে একবার ডেটা চারপাশে পাস করা শুরু হয়ে গেলে, বাগগুলি খুঁজে পাওয়ার জন্য কঠোরভাবে পরিচয় না করানোর জন্য আরও কাঠামোগত উপায়ে / সাধারণত পছন্দ করা উচিত (আপনি টাইপ সিস্টেমটির পাশ দিয়ে যাচ্ছেন)। তবে, আপনি যদি কোনও আপস খুঁজতে চান, তবে অন্য উপায়টি হল সাধারণ জেনারিক অভিধানটি পাস করা। সি # অভিধানের সূচনা এই দিনগুলিতে ব্যবহার করা বেশ সুবিধাজনক use
জোনাস

কিছু ক্ষেত্রে রয়েছে যেখানে আপনি জেনেরিক বাস্তবায়ন চান এবং কঠোর প্রকারের অর্থ পাস করার অর্থ সম্ভবত স্যুইচিং বা কারখানার বাস্তবায়ন যা কোডটি ফোটানো শুরু করে। যদি আপনার সত্যিকার অর্থে গতিশীল পরিস্থিতি থাকে এবং আপনি যে ডেটা গ্রহণ করছেন তা সামলানোর জন্য কিছুটা প্রতিফলন মনে করেন না, তবে এটি সঠিক। @ টিম এস উত্তরের জন্য ধন্যবাদ
ল্যারি স্মিথ

42

আপনি এটি এর মতো করতে পারেন:

public void LogEmployees<T>(List<T> list) // Or IEnumerable<T> list
{
    foreach (T item in list)
    {

    }
}

... তবে আপনি প্রতিটি আইটেমের সাথে বেশি কিছু করতে পারবেন না। আপনি টসস্ট্রিংকে কল করতে পারেন, তবে আপনি সরাসরি (বলে) Nameএবং Idসরাসরি ব্যবহার করতে পারবেন না ।


2
where T : some typeটাইপটি সংকীর্ণ করতে আপনি প্রথম লাইনের শেষে ব্যবহার করতে পারেন । এই মুহুর্তে, যদিও, একটি সাধারণ ধরণের ইন্টারফেসের একটি নির্দিষ্ট ধরণের আশা করা একটি ইন্টারফেসের আশা করা আরও অর্থবোধ করে। :)
ক্যাসঅনমার্স

9
@ ডি_আর_উ: আপনি where T : some typeবেনামে প্রকারের সাথে ব্যবহার করতে পারবেন না , কারণ তারা কোনও ধরণের ইন্টারফেস প্রয়োগ করে না ...
জন স্কিটে

@ ডিলেভ: আপনি এটি করতে পারবেন না, ফোরচের জন্য গেটইনুমেরেটর বাস্তবায়নের ক্ষেত্রে পরিবর্তনশীল পুনরাবৃত্তি হওয়া প্রয়োজন এবং বেনামে এই ধরণের গ্যারান্টি নেই।
ক্যাসঅনমার্স

1
@ জোন স্কিটি: ভাল কথা, আজ সকালে আমার মস্তিষ্ক আন্ডারপাওয়ার হয়েছে।
ক্যাসঅনমার্স

1
@JonSkeet। আমি মনে করি আপনি টি এখনও কোনও বেনামে টাইপ না করে সম্পত্তিটি অ্যাক্সেস / সেট করতে প্রতিবিম্বটি ব্যবহার করতে পারেন? আমি এমন একটি মামলার কথা ভাবছি যেখানে কেউ একটি "নির্বাচন করুন *" বিবৃতি লিখেছেন এবং আপনার বেনামে অবজেক্টের একই নামযুক্ত বৈশিষ্ট্যগুলিতে কোয়েরি ফলাফলের মানচিত্র থেকে কোন কলামগুলি সংজ্ঞায়িত করতে একটি বেনাম (বা সংজ্ঞায়িত) শ্রেণি ব্যবহার করেছেন।
সি তেওয়াল্ট

19

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

আপনার সেরা বেট হ'ল একটি প্রকার তৈরি করা এবং সেটিকে কোয়েরি থেকে ফেরত হিসাবে ব্যবহার করা এবং তারপরে এটি ফাংশনে প্রেরণ করা। উদাহরণ স্বরূপ,

struct Data {
  public string ColumnName; 
}

var query = (from name in some.Table
            select new Data { ColumnName = name });
MethodOp(query);
...
MethodOp(IEnumerable<Data> enumerable);

যদিও এই ক্ষেত্রে, আপনি কেবলমাত্র একটি একক ক্ষেত্র নির্বাচন করছেন, তাই সরাসরি ক্ষেত্রটি সরাসরি নির্বাচন করা সহজ হতে পারে। এটি ক্যোয়ারিকে IEnumerableক্ষেত্রের ধরণ হিসাবে টাইপ করার কারণ করবে । এক্ষেত্রে কলামের নাম।

var query = (from name in some.Table select name);  // IEnumerable<string>

আমার উদাহরণটি একটি ছিল, তবে বেশিরভাগ সময় এটি বেশি থাকে। কাজের মাধ্যমে আপনার উত্তর (এবং এখন বেশ স্পষ্টভাবে)। যদিও এটি ভাবতে আমার কেবল দুপুরের খাবারের জন্য বিরতি দরকার ছিল ;-)
টনি ট্রম্বাথ-ড্রেক

অবগতির জন্য: থেকে মার্জ করা হয়েছে stackoverflow.com/questions/775387/...
Shog9

একটি সতর্কতা হ'ল আপনি যখন একটি যথাযথ শ্রেণি তৈরি করেন তখন Equalsআচরণ পরিবর্তন হয়। অর্থাৎ আপনাকে এটি প্রয়োগ করতে হবে। (আমি এই
তাত্পর্যটি

11

প্যারামিটারের ধরন না থাকলে আপনি কোনও জেনারিক ফাংশনে বেনামে টাইপ করতে পারবেন না object

public void LogEmployees (object obj)
{
    var list = obj as IEnumerable(); 
    if (list == null)
       return;

    foreach (var item in list)
    {

    }
}

বেনামি ধরণগুলি একটি পদ্ধতির মধ্যে স্বল্পমেয়াদী ব্যবহারের জন্য উদ্দিষ্ট।

এমএসডিএন থেকে - নামবিহীন প্রকার :

আপনি কোনও ক্ষেত্র, সম্পত্তি, কোনও ইভেন্ট বা কোনও পদ্ধতির রিটার্নের ধরণের নাম বেনামি প্রকার হিসাবে ঘোষণা করতে পারবেন না। একইভাবে, আপনি কোনও বেনামি প্রকার হিসাবে কোনও পদ্ধতি, সম্পত্তি, নির্মাতা বা সূচকের আনুষ্ঠানিক প্যারামিটারটি ঘোষণা করতে পারবেন না। কোনও বেনামি প্রকার, বা কোনও সংগ্রহের মধ্যে বেনামে টাইপ করে এমন কোনও সংগ্রহকে কোনও পদ্ধতির আর্গুমেন্ট হিসাবে পাস করতে আপনি প্যারামিটারটিকে টাইপ অবজেক্ট হিসাবে ঘোষণা করতে পারেন । তবে এটি করার ফলে শক্তিশালী টাইপিংয়ের উদ্দেশ্য হ্রাস পায়।

(জোর আমার)


হালনাগাদ

আপনি যা চান তা অর্জন করতে আপনি জেনেরিকগুলি ব্যবহার করতে পারেন:

public void LogEmployees<T>(IEnumerable<T> list)
{
    foreach (T item in list)
    {

    }
}

4
যদি আপনি পদ্ধতিগুলিতে বেনাম প্রকারগুলি (বা কোনও বেনামে প্রকারের সংগ্রহ) পাস করতে না পারেন তবে পুরো লিনকিউ ব্যর্থ হবে। আপনি এটি করতে পারেন, পদ্ধতিটি সম্পূর্ণ জেনেরিক হতে হবে, বেনামি ধরণের বৈশিষ্ট্যগুলি ব্যবহার না করে।
জন স্কিটি

2
পুনরায় object- বাdynamic ; পি
মার্ক গ্র্যাভেল

"হিসাবে" দিয়ে কাস্টিং করা থাকলে তালিকাটি নাল কিনা তা আপনার পরীক্ষা করা উচিত
অ্যালেক্স

"পারে"! = "করতে হবে"। ব্যবহার objectআমার উত্তর অনুযায়ী, একটি পদ্ধতি বেনামী ধরনের জেনেরিক উপার্জন হিসাবে একই নয়।
জন স্কেটি

8

সাধারণত, আপনি জেনেরিক দিয়ে এটি করেন, উদাহরণস্বরূপ:

MapEntToObj<T>(IQueryable<T> query) {...}

সংকলকটি Tতখন আপনি কল করার সময় অনুমান করা উচিত MapEntToObj(query)। পদ্ধতির ভিতরে আপনি কী করতে চান তা পুরোপুরি নিশ্চিত নয়, সুতরাং এটি দরকারী কিনা তা আমি বলতে পারছি না ... সমস্যাটি হ'ল MapEntToObjআপনার অভ্যন্তরে এখনও নামটির নাম রাখা যায় না T- আপনি এটি করতে পারেন:

  • এর সাথে অন্যান্য জেনেরিক পদ্ধতিগুলি কল করুন T
  • প্রতিফলন ব্যবহার করেন তার উপর Tকিছু করার

তবে এগুলি ছাড়াও, বেনামে ধরণের হেরফের করা বেশ শক্ত - কারণ তা অপরিবর্তনীয় ;- পি

আরেকটি কৌশল (যখন ডেটা বের করার সময়) একটি নির্বাচককে পাস করাও হয় - যেমন:

Foo<TSource, TValue>(IEnumerable<TSource> source,
        Func<TSource,string> name) {
    foreach(TSource item in source) Console.WriteLine(name(item));
}
...
Foo(query, x=>x.Title);

1
নতুন কিছু শিখেছেন, জানেন না যে নামবিহীন প্রকারগুলি পরিবর্তনযোগ্য! ;)
অ্যানি লাগাং

1
@ অ্যানেলাগ্যাং যা সত্যই সংকলকটির সাথে সম্পর্কিত, যেহেতু এটি তাদের তৈরি করে। ভিবি.এনইটি-তে আনয়ন-প্রকারগুলি পরিবর্তনযোগ্য হতে পারে।
মার্ক Gravell

1
অবগতির জন্য: থেকে মার্জ করা হয়েছে stackoverflow.com/questions/775387/...
Shog9

7

আপনি নিম্নলিখিত কৌশলটির সাথে জেনেরিকগুলি ব্যবহার করতে পারেন (বেনামে টাইপ করাতে কাস্টিং):

public void LogEmployees<T>(IEnumerable<T> list)
{
    foreach (T item in list)
    {
        var typedItem = Cast(item, new { Name = "", Id = 0 });
        // now you can use typedItem.Name, etc.
    }
}

static T Cast<T>(object obj, T type)
{
    return (T)obj;
}

6

"গতিশীল" এই উদ্দেশ্যে ব্যবহার করা যেতে পারে।

var anonymousType = new { Id = 1, Name = "A" };

var anonymousTypes = new[] { new { Id = 1, Name = "A" }, new { Id = 2, Name = "B" };

private void DisplayAnonymousType(dynamic anonymousType)
{
}

private void DisplayAnonymousTypes(IEnumerable<dynamic> anonymousTypes)
{
   foreach (var info in anonymousTypes)
   {

   }
}

1
এটাই সঠিক উত্তর! এটির জন্য আরও ভালবাসার দরকার আছে :)
কোরায়েম

2

বেনামে টাইপ করার পরিবর্তে গতিশীল টাইপের একটি তালিকা পাস করুন:

  1. var dynamicResult = anonymousQueryResult.ToList<dynamic>();
  2. পদ্ধতির স্বাক্ষর: DoSomething(List<dynamic> _dynamicResult)
  3. কল পদ্ধতি: DoSomething(dynamicResult);
  4. সম্পন্ন.

পেটার ইভানভকে ধন্যবাদ !


0

যদি আপনি জানেন, আপনার ফলাফলগুলি একটি নির্দিষ্ট ইন্টারফেস প্রয়োগ করে আপনি ইন্টারফেসটি ডেটাটাইপ হিসাবে ব্যবহার করতে পারেন:

public void LogEmployees<T>(IEnumerable<T> list)
{
    foreach (T item in list)
    {

    }
}

0

আমি IEnumerable<object>যুক্তির জন্য টাইপ হিসাবে ব্যবহার করব । তবে অনিবার্য স্পষ্ট কাস্টের জন্য দুর্দান্ত লাভ নয়। চিয়ার্স

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.