সি # তে বেনামে টাইপ করা


104

আমার কাছে একটি কোয়েরি রয়েছে যা একটি বেনামি ধরণ দেয় এবং কোয়েরিটি একটি পদ্ধতিতে। আপনি এটি কীভাবে লিখবেন:

public "TheAnonymousType" TheMethod(SomeParameter)
{
  using (MyDC TheDC = new MyDC())
  {
     var TheQueryFromDB = (....
                           select new { SomeVariable = ....,
                                        AnotherVariable = ....}
                           ).ToList();

      return "TheAnonymousType";
    }
}

5
কেন আপনি কোনও বেনামি টাইপ ফিরে আসতে চান? আপনি সম্ভবত অন্য কোথাও এই ফলাফলটি ব্যবহার করতে পারেন?
ইয়াক


6
@ ইয়াক আপনি যদি জসন বা এমন কিছু ফিরে যাচ্ছেন যেখানে সি # টাইপের কোনও ব্যাপার নেই
aw04

10
আমি মনে করি না যে এই প্রশ্নটি অযৌক্তিক। আমার আসলে এটি বেশ কয়েকবার করা দরকার। সত্তা ফ্রেমওয়ার্ক ব্যবহার করার সময় এটি আরও স্পষ্ট হয় এবং আপনি আপনার ক্যোয়ারীটি একটি ফাংশনে করতে চান এবং ফলাফলগুলি বেশ কয়েকটি জায়গায় ব্যবহার করতে চান। স্ক্রিনে ফলাফলগুলি প্রদর্শন করার সময় এবং প্রতিবেদনে একই ফলাফল ব্যবহার করার সময় বা এক্সেল এক্সপোর্ট করার সময় আমার বেশিরভাগ ক্ষেত্রে এটি প্রয়োজন। ক্যোয়ারিতে অনেকগুলি ফিল্টার এবং ইউআই থেকে থাকতে পারে। আপনি বেশ কয়েকটি জায়গায় একই ক্যোয়ারীটি সত্যই তৈরি করতে চান না বা আপনি ফলাফলগুলিতে যুক্ত করতে চাইলে সহজেই সিঙ্ক থেকে বেরিয়ে আসতে পারেন
কেভবো

উত্তর:


95

আপনি পারবেন না।

আপনি শুধুমাত্র আসতে পারেন object, অথবা বস্তুর ধারক, যেমন IEnumerable<object>, IList<object>ইত্যাদি


53
বা dynamic। এটি এর সাথে কাজ করা এত সহজ করে তোলে।
vcsjones

আহ ঠিক আছে, সুতরাং আপনি কেবল কোনও পদ্ধতির মধ্যে বেনামে ব্যবহার করতে পারেন তবে ফেরতের মান হিসাবে না?
ফ্রেঞ্চি

4
@ ফ্রাঞ্চি: হ্যাঁ, কেবল সদস্যের দেহের ভিতরে। আপনি যদি এটি ফিরিয়ে দিতে চান - এটি একটি সুপরিচিত প্রকার তৈরি করুন।
আবাতিশ শেভ

11
ডায়নামিক ব্যবহার কোনও সমাধান নয়, বেনামে টাইপের ক্ষেত্রগুলি সর্বজনীন নয়, সেগুলি অভ্যন্তরীণ।
হ্যানস প্যাস্যান্ট

8
@ હંসপ্যাস্যান্ট ধরে নিচ্ছেন যে আহ্বানকারী একই সমাবেশে আছেন তবে এটি এখনও কিছুটা কার্যকর useful এটি মূল্যবান জন্য, ক্ষেত্রগুলি সর্বজনীন - প্রকারটি অভ্যন্তরীণ। আমি সাধারণত শিবিরে আছি যে আপনাকে আর কোনও বেনামি টাইপ দেওয়া উচিত নয়।
vcsjones

42

আপনি ফিরে আসতে পারেন dynamicযা আপনাকে বেনামে টাইপের একটি রানটাইম চেক সংস্করণ দিবে তবে কেবল নেট 4+ এ


34

সি # 7 এ আমরা এটি সম্পাদন করতে টিপলগুলি ব্যবহার করতে পারি:

public List<(int SomeVariable, string AnotherVariable)> TheMethod(SomeParameter)
{
  using (MyDC TheDC = new MyDC())
  {
     var TheQueryFromDB = (....
                       select new { SomeVariable = ....,
                                    AnotherVariable = ....}
                       ).ToList();

      return TheQueryFromDB
                .Select(s => (
                     SomeVariable = s.SomeVariable, 
                     AnotherVariable = s.AnotherVariable))
                 .ToList();
  }
}

System.ValueTupleযদিও আপনাকে নুগেট প্যাকেজ ইনস্টল করতে হবে ।


এটি ঠিক আমি যা খুঁজছিলাম, জেএস টাইপের মতো শোনাচ্ছে
ফ্যাব্রিস টি

28

আপনি বেনামে টাইপ করতে পারবেন না। আপনি কি এমন কোনও মডেল তৈরি করতে পারেন যা ফেরত যেতে পারে? অন্যথায়, আপনি অবশ্যই একটি ব্যবহার করুনobject

এই বিষয়টিতে জন স্কিটি রচিত একটি নিবন্ধ এখানে দেওয়া হয়েছে

নিবন্ধ থেকে কোড:

using System;

static class GrottyHacks
{
    internal static T Cast<T>(object target, T example)
    {
        return (T) target;
    }
}

class CheesecakeFactory
{
    static object CreateCheesecake()
    {
        return new { Fruit="Strawberry", Topping="Chocolate" };
    }

    static void Main()
    {
        object weaklyTyped = CreateCheesecake();
        var stronglyTyped = GrottyHacks.Cast(weaklyTyped,
            new { Fruit="", Topping="" });

        Console.WriteLine("Cheesecake: {0} ({1})",
            stronglyTyped.Fruit, stronglyTyped.Topping);            
    }
}

বা, এখানে অন্য অনুরূপ নিবন্ধ

বা অন্যরা যেমন মন্তব্য করছেন আপনি ব্যবহার করতে পারেন dynamic


8
অবশ্যই আমি একটি টাইপ তৈরি করতে পারি; আমি এই কাজটি এড়াতে চাইছিলাম।
ফ্রেঞ্চি

প্রথম লিঙ্কটি মারা গেছে, এটি অন্য কোথাও স্থানান্তরিত হয়েছে কিনা তা আপনি কি জানবেন না?
রুমী

18

ফিরতি যখন প্রয়োজন হয় তখন আপনি বেনামে টাইপের বিকল্প হিসাবে টুপল ক্লাসটি ব্যবহার করতে পারেন:

দ্রষ্টব্য: টিপল পর্যন্ত 8 টি পরামিতি থাকতে পারে।

return Tuple.Create(variable1, variable2);

বা, মূল পোস্ট থেকে উদাহরণস্বরূপ:

public List<Tuple<SomeType, AnotherType>> TheMethod(SomeParameter)
{
  using (MyDC TheDC = new MyDC())
  {
     var TheQueryFromDB = (....
                           select Tuple.Create(..., ...)
                           ).ToList();

      return TheQueryFromDB.ToList();
    }
}

http://msdn.microsoft.com/en-us/library/system.tuple(v=vs.110).aspx


10

সি # সংকলক একটি দুটি পর্যায়ের সংকলক। প্রথম পর্যায়ে এটি কেবল নেমস্পেসগুলি, শ্রেণিক্রমের স্তরক্রম, পদ্ধতিতে স্বাক্ষর ইত্যাদি পরীক্ষা করে। মেথড বডিগুলি কেবলমাত্র দ্বিতীয় পর্যায়ে সংকলিত হয়।

পদ্ধতির বডি সংকলন না করা অবধি অনামী নাম নির্ধারণ করা হয় না।

সুতরাং সংকলকটির প্রথম পর্যায়ে রিটার্নের ধরণটি নির্ধারণের কোনও উপায় নেই।

এ কারণেই বেনামে টাইপগুলি রিটার্ন টাইপ হিসাবে ব্যবহার করা যায় না।

অন্যরা যেমন পরামর্শ দিয়েছে যে আপনি যদি নেট নেট 4.0 বা গ্রেটার ব্যবহার করছেন তবে আপনি ব্যবহার করতে পারেন Dynamic

আমি যদি আপনি হয়ে থাকি তবে আমি সম্ভবত একটি টাইপ তৈরি করে সেই ধরণটি পদ্ধতি থেকে ফিরিয়ে আনতাম। এইভাবে ভবিষ্যতের প্রোগ্রামারদের পক্ষে যারা আপনার কোড বজায় রাখে এবং আরও পাঠযোগ্য read


8

তিনটি বিকল্প:

বিকল্প 1:

public class TheRepresentativeType {
    public ... SomeVariable {get;set;}
    public ... AnotherVariable {get;set;}
}

public IEnumerable<TheRepresentativeType> TheMethod(SomeParameter)
{
   using (MyDC TheDC = new MyDC())
   {
     var TheQueryFromDB = (....
                           select new TheRepresentativeType{ SomeVariable = ....,
                                        AnotherVariable = ....}
                           ).ToList();

     return TheQueryFromDB;
   } 
}

বিকল্প 2:

public IEnumerable TheMethod(SomeParameter)
{
   using (MyDC TheDC = new MyDC())
   {
     var TheQueryFromDB = (....
                           select new TheRepresentativeType{ SomeVariable = ....,
                                        AnotherVariable = ....}
                           ).ToList();
     return TheQueryFromDB;
   } 
}

আপনি এটি অবজেক্ট হিসাবে পুনরাবৃত্তি করতে পারেন

বিকল্প 3:

public IEnumerable<dynamic> TheMethod(SomeParameter)
{
   using (MyDC TheDC = new MyDC())
   {
     var TheQueryFromDB = (....
                           select new TheRepresentativeType{ SomeVariable = ....,
                                        AnotherVariable = ....}
                           ).ToList();

     return TheQueryFromDB; //You may need to call .Cast<dynamic>(), but I'm not sure
   } 
}

এবং আপনি এটিকে একটি গতিশীল অবজেক্ট হিসাবে পুনরাবৃত্তি করতে এবং সরাসরি তাদের বৈশিষ্ট্যগুলিতে অ্যাক্সেস করতে সক্ষম হবেন


3

আপনি এই ক্ষেত্রে অবজেক্টের তালিকা ফিরে আসতে পারেন।

public List<object> TheMethod(SomeParameter)
{
  using (MyDC TheDC = new MyDC())
  {
     var TheQueryFromDB = (....
                           select new { SomeVariable = ....,
                                        AnotherVariable = ....}
                           ).ToList();

      return TheQueryFromDB ;
    }
}

3

সি # .0.০ ব্যবহার করে আমরা এখনও বেনামে প্রকারগুলি ফিরিয়ে দিতে পারি না তবে আমাদের কাছে টুপল প্রকারের সমর্থন রয়েছে এবং আমরা tuple( System.ValueTuple<T1,T2>এই ক্ষেত্রে) এর সংগ্রহ ফিরিয়ে দিতে পারি । বর্তমানে Tuple types এক্সপ্রেশন ট্রিগুলিতে সমর্থিত নয় এবং আপনার মেমরিতে ডেটা লোড করতে হবে।

আপনি যে কোডটি চান তার সংক্ষিপ্ততম সংস্করণটি এর মতো দেখতে পাওয়া যাবে:

public IEnumerable<(int SomeVariable, object AnotherVariable)> TheMethod()
{
    ...

    return (from data in TheDC.Data
        select new { data.SomeInt, data.SomeObject }).ToList()
        .Select(data => (SomeVariable: data.SomeInt, AnotherVariable: data.SomeObject))
}

বা সাবলীল লিনাক সিনট্যাক্স ব্যবহার করে:

return TheDC.Data
    .Select(data => new {SomeVariable: data.SomeInt, AnotherVariable: data.SomeObject})
    .ToList();
    .Select(data => (SomeVariable: data.SomeInt, AnotherVariable: data.SomeObject))

সি # 7.1 ব্যবহার করে আমরা টিপলের বৈশিষ্ট্যগুলির নাম বাদ দিতে পারি এবং এগুলি বেনামে প্রকারের মতো কাজ করে যেমন টিপল সূচনা থেকে অনুমান করা হবে:

select (data.SomeInt, data.SomeObject)
// or
Select(data => (data.SomeInt, data.SomeObject))

2
public List<SomeClass> TheMethod(SomeParameter)
{
  using (MyDC TheDC = new MyDC())
  {
     var TheQueryFromDB = (....
                           select new SomeClass{ SomeVariable = ....,
                                        AnotherVariable = ....}
                           ).ToList();

      return TheQueryFromDB.ToList();
    }
}

public class SomeClass{
   public string SomeVariable{get;set}
   public string AnotherVariable{get;set;}
}

আপনার নিজের শ্রেণি তৈরি করা এবং এর জন্য অনুসন্ধান করা আমার পক্ষে সেরা সমাধান। আমি যতটা জানি আপনি অন্য কোনও পদ্ধতিতে বেনামে টাইপের রিটার্ন মানগুলি ব্যবহার করতে পারবেন না, কারণ এটি কেবল স্বীকৃত হবে না ow তবে, সেগুলি একই ব্যবহার করা যেতে পারে পদ্ধতি আমি তাদের হিসাবে IQueryableবা তাদের হিসাবে ফিরে IEnumerableআসতাম, যদিও এটি আপনাকে বেনামে টাইপের ভেরিয়েবলের ভিতরে কী রয়েছে তা দেখতে দেয় না।

আমি এর আগে কিছু কোড নিয়েছিলাম যখন আমি কিছু কোড রিফ্যাক্টর করার চেষ্টা করছিলাম, আপনি এটি এখানে পরীক্ষা করতে পারেন: রিফ্যাক্টরিং এবং পৃথক পদ্ধতি তৈরি করা


2

প্রতিচ্ছবি সহ।

public object tst() {
    var a = new {
        prop1 = "test1",
        prop2 = "test2"
    };

    return a;
}


public string tst2(object anonymousObject, string propName) {
    return anonymousObject.GetType().GetProperties()
        .Where(w => w.Name == propName)
        .Select(s => s.GetValue(anonymousObject))
        .FirstOrDefault().ToString();
}

নমুনা:

object a = tst();
var val = tst2(a, "prop2");

আউটপুট:

test2

1

আপনি কেবল গতিশীল কীওয়ার্ড ব্যবহার করতে পারেন,

   dynamic obj = GetAnonymousType();

   Console.WriteLine(obj.Name);
   Console.WriteLine(obj.LastName);
   Console.WriteLine(obj.Age); 


   public static dynamic GetAnonymousType()
   {
       return new { Name = "John", LastName = "Smith", Age=42};
   }

তবে ডায়নামিক টাইপ কীওয়ার্ডের সাহায্যে আপনি সংকলন সময় সুরক্ষা, আইডিই ইন্টেলিজেন্স ইত্যাদি হ্রাস করবেন ...


1

কোনও নির্দিষ্ট ব্যবহারের ক্ষেত্রে কোনও পদ্ধতি থেকে কোনও বেনামে ফিরে আসা আসলে সম্ভব। চল একটু দেখি!

সি # 7 দিয়ে কোনও পদ্ধতি থেকে বেনামে প্রকারগুলি ফেরানো সম্ভব, যদিও এটি সামান্য প্রতিবন্ধকতা নিয়ে আসে। আমরা স্থানীয় ফাংশন নামে একটি নতুন ভাষা বৈশিষ্ট্য ব্যবহার করতে যাচ্ছি একত্রে ইন্ডিয়ারেশন ট্রিক হবে (ইন্ডিয়ারেশনের অন্য স্তরটি কোনও প্রোগ্রামিং চ্যালেঞ্জ সমাধান করতে পারে, তাই না?)

আমি সম্প্রতি চিহ্নিত একটি ব্যবহারের কেস এখানে। আমি সমস্ত কনফিগারেশন মানগুলি এগুলি লোড করার পরে লগ করতে চাইAppSettings । কেন? কারণ অনুপস্থিত মানগুলির চারপাশে কিছু যুক্তি রয়েছে যা ডিফল্ট মানগুলিতে প্রত্যাবর্তন করে, কিছু পার্সিং এবং আরও অনেক কিছু। লজিক প্রয়োগের পরে মানগুলিতে লগ করার একটি সহজ উপায় হ'ল সেগুলি সমস্ত শ্রেণিতে স্থাপন করা এবং এটি লগ-ফাইলে সিরিয়ালকরণ করা (লগ 4 নেট ব্যবহার করে)। আমি সেটিংসের সাথে ডিল করার জটিল যুক্তিটি সজ্জিত করতে এবং তাদের সাথে আমার যা করা দরকার তা থেকে পৃথক করতে চাই। নামমাত্র শ্রেণি তৈরি না করে যা কেবলমাত্র একক ব্যবহারের জন্য বিদ্যমান!

আসুন দেখুন কীভাবে এটি একটি স্থানীয় ফাংশন ব্যবহার করে এটি সমাধান করা যায় যা একটি বেনামি প্রকার তৈরি করে।

public static HttpClient CreateHttpClient()
{
    // I deal with configuration values in this slightly convoluted way.
    // The benefit is encapsulation of logic and we do not need to
    // create a class, as we can use an anonymous class.
    // The result resembles an expression statement that
    // returns a value (similar to expressions in F#)
    var config = Invoke(() =>
    {
        // slightly complex logic with default value
        // in case of missing configuration value
        // (this is what I want to encapsulate)
        int? acquireTokenTimeoutSeconds = null;
        if (int.TryParse(ConfigurationManager.AppSettings["AcquireTokenTimeoutSeconds"], out int i))
        {
            acquireTokenTimeoutSeconds = i;
        }

        // more complex logic surrounding configuration values ...

        // construct the aggregate configuration class as an anonymous type!
        var c = new
        {
            AcquireTokenTimeoutSeconds =
                acquireTokenTimeoutSeconds ?? DefaultAcquireTokenTimeoutSeconds,
            // ... more properties
        };

        // log the whole object for monitoring purposes
        // (this is also a reason I want encapsulation)
        Log.InfoFormat("Config={0}", c);
        return c;
    });

    // use this configuration in any way necessary...
    // the rest of the method concerns only the factory,
    // i.e. creating the HttpClient with whatever configuration
    // in my case this:
    return new HttpClient(...);

    // local function that enables the above expression
    T Invoke<T>(Func<T> func) => func.Invoke();
}

আমি একটি বেনাম শ্রেণি তৈরিতে সাফল্য পেয়েছি CreateHttpClientএবং এর ভিতরে এবং তার নিজের "এক্সপ্রেশন" এর মধ্যে জটিল সেটিংস পরিচালনার সাথে যুক্ত হওয়ার যুক্তিকে আবৃত করেছি । এটি ওপি ঠিক যা চেয়েছিল তা নাও হতে পারে তবে এটি বেনামে ধরণের হালকা ওজনের যা বর্তমানে আধুনিক সি # তে সম্ভব।


0

আর একটি বিকল্প অটোম্যাপার ব্যবহার করা যেতে পারে: যতক্ষণ না জনসাধারণের সম্পত্তি মেলে ততক্ষণ আপনি আপনার বেনামে ফিরে আসা বস্তু থেকে যে কোনও ধরণের রূপান্তর করবেন। মূল বিষয়গুলি হ'ল রিটার্নিং অবজেক্ট, লিনক এবং অটোমাপার ব্যবহার করুন। (বা সিরিয়ালযুক্ত জসন ইত্যাদি ফেরত দেওয়ার অনুরূপ ধারণা ব্যবহার করুন বা প্রতিচ্ছবি ব্যবহার করুন ..)

using System.Linq;
using System.Reflection;
using AutoMapper;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;

namespace UnitTestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            var data = GetData();

            var firts = data.First();

            var info = firts.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).First(p => p.Name == "Name");
            var value = info.GetValue(firts);

            Assert.AreEqual(value, "One");
        }


        [TestMethod]
        public void TestMethod2()
        {
            var data = GetData();

            var config = new MapperConfiguration(cfg => cfg.CreateMissingTypeMaps = true);
            var mapper = config.CreateMapper();

            var users = data.Select(mapper.Map<User>).ToArray();

            var firts = users.First();

            Assert.AreEqual(firts.Name, "One");

        }

        [TestMethod]
        public void TestMethod3()
        {
            var data = GetJData();


            var users = JsonConvert.DeserializeObject<User[]>(data);

            var firts = users.First();

            Assert.AreEqual(firts.Name, "One");

        }

        private object[] GetData()
        {

            return new[] { new { Id = 1, Name = "One" }, new { Id = 2, Name = "Two" } };
        }

        private string GetJData()
        {

            return JsonConvert.SerializeObject(new []{ new { Id = 1, Name = "One" }, new { Id = 2, Name = "Two" } }, Formatting.None);
        }

        public class User
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
    }

}

0

এখন বিশেষত স্থানীয় ফাংশন সহ, তবে আপনি সর্বদা এটি এমন কোনও প্রতিনিধিকে পাস করে করতে পারেন যা বেনামে টাইপ করে।

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

// returning an anonymous type
// look mom no casting
void LookMyChildReturnsAnAnonICanConsume()
{
    // if C# had first class functions you could do
    // var anonyFunc = (name:string,id:int) => new {Name=name,Id=id};
    var items = new[] { new { Item1 = "hello", Item2 = 3 } };
    var itemsProjection =items.Select(x => SomeLogic(x.Item1, x.Item2, (y, i) => new { Word = y, Count = i} ));
    // same projection = same type
    var otherSourceProjection = SomeOtherSource((y,i) => new {Word=y,Count=i});
    var q =
        from anony1 in itemsProjection
        join anony2 in otherSourceProjection
            on anony1.Word equals anony2.Word
        select new {anony1.Word,Source1Count=anony1.Count,Source2Count=anony2.Count};
    var togetherForever = itemsProjection.Concat(otherSourceProjection).ToList();
}

T SomeLogic<T>(string item1, int item2, Func<string,int,T> f){
    return f(item1,item2);
}
IEnumerable<T> SomeOtherSource<T>(Func<string,int,T> f){
    var dbValues = new []{Tuple.Create("hello",1), Tuple.Create("bye",2)};
    foreach(var x in dbValues)
        yield return f(x.Item1,x.Item2);
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.