বৈশিষ্ট্যগুলি ডিসিরিয়ালাইজ করতে Json.NET রূপান্তরকারী ব্যবহার করে


88

আমার একটি শ্রেণিবদ্ধ সংজ্ঞা রয়েছে যাতে এমন একটি সম্পত্তি রয়েছে যা একটি ইন্টারফেস দেয়।

public class Foo
{ 
    public int Number { get; set; }

    public ISomething Thing { get; set; }
}

Json.NET ব্যবহার করে ফু ক্লাসিকে সিরিয়ালকরণ করার চেষ্টা আমাকে একটি ত্রুটি বার্তা দেয় যেমন "'আইসোমেথিং' টাইপের উদাহরণ তৈরি করতে পারেনি IS

এমন কোনও জাসন.এনইটি অ্যাট্রিবিউট বা রূপান্তরকারী আছে যা আমাকে ডিসেরায়ালনের Somethingসময় ব্যবহারের জন্য একটি কংক্রিট শ্রেণি নির্দিষ্ট করতে দেয়?


আমি বিশ্বাস করি যে আপনার কোনও সম্পত্তি নাম নির্দিষ্ট করা দরকার যা আইসোমিংটি / সেটগুলি নির্ধারণ করে
ram

আমার আছে. আমি সি # 3.5 তে প্রবর্তিত স্বয়ংক্রিয় প্রয়োগকৃত বৈশিষ্ট্যের জন্য শর্টহ্যান্ড ব্যবহার করছি। msdn.microsoft.com/en-us/library/bb384054.aspx
dthrasher

4
কি ধরণের কি না। আমি মনে করি রাম ঠিক, আপনার এখনও একটি সম্পত্তি নাম প্রয়োজন। আমি জানি এটি আপনার সমস্যার সাথে সম্পর্কিত নয়, তবে উপরের আপনার মন্তব্য আমাকে মনে করেছে যে আমি .NET এ নতুন কিছু বৈশিষ্ট্য হারিয়েছি যা আপনাকে নাম ছাড়াই সম্পত্তি নির্দিষ্ট করার অনুমতি দিয়েছে।
মিঃ মোজ

উত্তর:


92

Json.NET এর সাথে আপনি যে কাজগুলি করতে পারেন তার মধ্যে একটি:

var settings = new JsonSerializerSettings();
settings.TypeNameHandling = TypeNameHandling.Objects;

JsonConvert.SerializeObject(entity, Formatting.Indented, settings);

TypeNameHandlingপতাকা একটি যোগ হবে $typeতাদেরকে JSON, যা Json.NET জানেন যে যা কংক্রিট টাইপ তা বস্তুর deserialize প্রয়োজন পারবেন সম্পত্তি। এটি আপনাকে ইন্টারফেস বা অ্যাবস্ট্রাক্ট বেস ক্লাসটি পূরণ করার সময় কোনও অবজেক্টকে ডিসরিয়ালাইজ করতে দেয়।

নেতিবাচক দিকটি হ'ল এটি খুব Json.NET- নির্দিষ্ট। $typeতাই যদি আপনি এটা টাইপ তথ্য সহ serializing করছি, একটি সম্পূর্ণ যোগ্যতাসম্পন্ন টাইপ হতে হবে ,, deserializer চাহিদা ভাল হিসাবে এটি বুঝতে সক্ষম হবে।

ডকুমেন্টেশন: জসন.এনইটি দিয়ে সিরিয়ালাইজেশন সেটিংস


মজাদার. আমি এই সঙ্গে চারপাশে খেলতে হবে। সুন্দর টিপ!
dthrasher

4
নিউটনসফট.জসনের ক্ষেত্রে এটি একই রকম কাজ করে তবে সম্পত্তিটি "ধরণের"
জাপ

এটা খুব সহজ ছিল!
শিমি ওয়েটজ্যান্ডলার

4
সম্ভাব্য সুরক্ষার সমস্যাগুলি ব্যবহার করার সময় এখানে নজর রাখুন TypeNameHandling। বিশদ বিবরণের জন্য নিউটনসফট জসনে টাইপনেম হ্যান্ডলিংয়ের সতর্কতা দেখুন ।
ডিবিসি

আমি গতকাল রূপান্তরকারীদের সাথে পাগলের মতো লড়াই করেছি এবং এটি ছিল আরও ভাল এবং আরও ভাল বোধগম্য, ধন্যবাদ !!!
হরোথেনিক

52

আপনি জসনকনভার্টার ক্লাস ব্যবহারের মাধ্যমে এটি অর্জন করতে পারেন। ধরুন আপনার ইন্টারফেসের সম্পত্তি সহ একটি শ্রেণি রয়েছে;

public class Organisation {
  public string Name { get; set; }

  [JsonConverter(typeof(TycoonConverter))]
  public IPerson Owner { get; set; }
}

public interface IPerson {
  string Name { get; set; }
}

public class Tycoon : IPerson {
  public string Name { get; set; }
}

আপনার JsonConverter অন্তর্নিহিত সম্পত্তি ক্রমিকায়ন এবং ডি-সিরিয়ালাইজ করার জন্য দায়ী;

public class TycoonConverter : JsonConverter
{
  public override bool CanConvert(Type objectType)
  {
    return (objectType == typeof(IPerson));
  }

  public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
  {
    return serializer.Deserialize<Tycoon>(reader);
  }

  public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
  {
    // Left as an exercise to the reader :)
    throw new NotImplementedException();
  }
}

আপনি যখন জসন.নাইটের মাধ্যমে ডিসরিয়ালাইজড কোনও সংস্থার সাথে কাজ করেন মালিকের সম্পত্তির জন্য অন্তর্নিহিত আইপারসন টাইকুন টাইপের হবে।


খুব সুন্দর. আমাকে কনভার্টারটি চেষ্টা করে দেখতে হবে।
dthrasher

4
ইন্টারফেসের একটি তালিকায় থাকলে "[জসনকনভার্টার (টাইফফ (টাইকুনকোনভার্টার))] ট্যাগটি কি এখনও কাজ করবে?
জিউভিক

40

যেমন পূর্বে উল্লিখিত হিসাবে টাইপনামহ্যান্ডলিং.অবজেক্টস বিকল্পের সাথে জাস্টসোনভার্ট.সরিয়ালাইজ অবজেক্টে কাস্টমাইজড জসনসিরাইজারসেটেটিংস অবজেক্টটি পাস করার পরিবর্তে.অবজেক্টস অপশনটি, আপনি কেবলমাত্র একটি নির্দিষ্ট বৈশিষ্ট্যযুক্ত সেই নির্দিষ্ট ইন্টারফেসের সম্পত্তি চিহ্নিত করতে পারেন যাতে উত্পন্ন জেএসওএন "$ প্রকার" বৈশিষ্ট্য দ্বারা প্রস্ফুটিত হবে না প্রতিটি বস্তুর উপর:

public class Foo
{
    public int Number { get; set; }

    // Add "$type" property containing type info of concrete class.
    [JsonProperty( TypeNameHandling = TypeNameHandling.Objects )]
    public ISomething { get; set; }
}

উজ্জ্বল। ধন্যবাদ :)
ড্যারেন ইয়াং

4
ইন্টারফেস বা বিমূর্ত শ্রেণীর সংগ্রহের জন্য সম্পত্তিটি হ'ল "আইটেমটাইপ নাম হ্যান্ডলিং"। উদাহরণস্বরূপ: [জসনপ্রপার্টি (আইটেমটাইপ নাম হ্যান্ডলিং = টাইপনামহ্যান্ডলিং.আউটো)]
অ্যান্থনি এফ

এই জন্য আপনাকে ধন্যবাদ!
ব্রুডার্ট

24

তৃতীয় পক্ষের নিউটোনসফট জসন রূপান্তরকারীটির অতি সাম্প্রতিক সংস্করণে আপনি ইন্টারফেসযুক্ত সম্পত্তি সম্পর্কিত একটি কংক্রিট টাইপ সহ একটি নির্মাতা সেট করতে পারেন।

public class Foo
{ 
    public int Number { get; private set; }

    public ISomething IsSomething { get; private set; }

    public Foo(int number, Something concreteType)
    {
        Number = number;
        IsSomething = concreteType;
    }
}

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

পুনশ্চ. এটি আপনাকে আপনার সেটটারগুলিকে ব্যক্তিগত করার অনুমতি দেয়।


6
ছাদ থেকে এই চিৎকার করা উচিত! সত্য, এটি কংক্রিট বাস্তবায়নে বাধা যুক্ত করে, তবে এটি যে পরিস্থিতিতে ব্যবহার করা যেতে পারে তার জন্য অন্যান্য পদ্ধতির তুলনায় এটি অনেক বেশি সোজা।
মার্ক মিউয়ার

4
যদি আমাদের একাধিক কনস্ট্রাক্টরের একাধিক কংক্রিট ধরণের থাকে তবে এটি কী এখনও জানতে পারবে?
তেওমান শিপাহি

4
আপনি অন্যথায় করতে হবে এমন সমস্ত বিভ্রান্ত বাজেটের তুলনায় এই উত্তরটি খুব মার্জিত। এটি গ্রহণযোগ্য উত্তর হওয়া উচিত। আমার ক্ষেত্রে একটি সতর্কতামূলক বিষয়, যদিও এটির কাজ করার জন্য আমাকে কন্সট্রাক্টরের আগে [জসনকন্সট্রাক্টর] যোগ করতে হয়েছিল .... আমার সন্দেহ যে আপনার কংক্রিট কনস্ট্রাক্টরগুলির মধ্যে একটিতে এটি ব্যবহার করা আপনার (৪ বছরের পুরানো) সমস্যার সমাধান করবে would @ তেমনশিপাহী
নসিটার সেবাহাত

@ ন্যাসিটারসভেহট আমি এখনই ফিরে যেতে পারি এবং আমার সমস্যাটি এখনই ঠিক করতে পারি :) যাইহোক আমি কী ছিল তা আমার মনে নেই তবে আমি যখন আবার তাকাব তখন এটি নির্দিষ্ট ক্ষেত্রে একটি ভাল সমাধান।
তেওমান শিপহি

আমরা এটিও ব্যবহার করি তবে আমি বেশিরভাগ ক্ষেত্রে রূপান্তরকেই পছন্দ করি কারণ কনস্ট্রাক্টরের সাথে কংক্রিটের ধরণটি প্রথম স্থানে সম্পত্তিটির জন্য একটি ইন্টারফেস ব্যবহারের উদ্দেশ্যকে পরাস্ত করে!
গাবি

19

একই সমস্যা ছিল তাই আমি আমার নিজের রূপান্তরকারী নিয়ে এসেছি যা জ্ঞাত প্রকারের যুক্তি ব্যবহার করে।

public class JsonKnownTypeConverter : JsonConverter
{
    public IEnumerable<Type> KnownTypes { get; set; }

    public JsonKnownTypeConverter(IEnumerable<Type> knownTypes)
    {
        KnownTypes = knownTypes;
    }

    protected object Create(Type objectType, JObject jObject)
    {
        if (jObject["$type"] != null)
        {
            string typeName = jObject["$type"].ToString();
            return Activator.CreateInstance(KnownTypes.First(x =>typeName.Contains("."+x.Name+",")));
        }

        throw new InvalidOperationException("No supported type");
    }

    public override bool CanConvert(Type objectType)
    {
        if (KnownTypes == null)
            return false;

        return (objectType.IsInterface || objectType.IsAbstract) && KnownTypes.Any(objectType.IsAssignableFrom);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // Load JObject from stream
        JObject jObject = JObject.Load(reader);
        // Create target object based on JObject
        var target = Create(objectType, jObject);
        // Populate the object properties
        serializer.Populate(jObject.CreateReader(), target);
        return target;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

আমি ডিসরিয়ালাইজেশন এবং সিরিয়ালাইজেশনের জন্য দুটি এক্সটেনশন পদ্ধতি সংজ্ঞায়িত করেছি:

public static class AltiJsonSerializer
{
    public static T DeserializeJson<T>(this string jsonString, IEnumerable<Type> knownTypes = null)
    {
        if (string.IsNullOrEmpty(jsonString))
            return default(T);

        return JsonConvert.DeserializeObject<T>(jsonString,
                new JsonSerializerSettings
                {
                    TypeNameHandling = TypeNameHandling.Auto, 
                    Converters = new List<JsonConverter>
                        (
                            new JsonConverter[]
                            {
                                new JsonKnownTypeConverter(knownTypes)
                            }
                        )
                }
            );
    }

    public static string SerializeJson(this object objectToSerialize)
    {
        return JsonConvert.SerializeObject(objectToSerialize, Formatting.Indented,
        new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.Auto});
    }
}

আপনি রূপান্তরকারী ধরণের তুলনা এবং সনাক্তকরণের নিজস্ব পদ্ধতিটি নির্ধারণ করতে পারেন, আমি কেবল শ্রেণীর নাম ব্যবহার করি।


4
এই জসনকনভার্টর দুর্দান্ত, আমি এটি ব্যবহার করেছিলাম তবে বেশ কয়েকটি সমস্যার মুখোমুখি হয়েছি আমি এইভাবে সমাধান করেছি: - জপসনসিরাইজার.ক্রেইট ডেফল্ট () ব্যবহারের পরিবর্তে পপুলেট করা, কারণ আমার অবজেক্টটির গভীরতর স্তরবিন্যাস ছিল। - নির্মাণকারীর পুনরুদ্ধার করতে এবং এটি তৈরি () পদ্ধতিতে প্রতিবিম্বিত করে
অরেল

3

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

public class Model
{
    [JsonConverter(typeof(ConcreteTypeConverter<Something>))]
    public ISomething TheThing { get; set; }
}

এটি স্রেফ স্পষ্টভাবে কংক্রিটের ধরণ উল্লেখ করে Json.Net থেকে ডিফল্ট সিরিয়ালাইজার প্রয়োগ ব্যবহার করে।

উত্স কোড এবং একটি ওভারভিউ এই ব্লগ পোস্টে উপলব্ধ


4
এটি একটি দুর্দান্ত সমাধান। চিয়ার্স
জনমেটা

2

আমি শুধু উদাহরণটি সম্পূর্ণ করতে চেয়েছিলাম যা @ ড্যানিয়েল টি। আমাদের উপরে দেখিয়েছিল:

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

var settings = new JsonSerializerSettings();
settings.TypeNameHandling = TypeNameHandling.Objects;
JsonConvert.SerializeObject(entity, Formatting.Indented, settings);

জসনকে ডিসিরিয়ালাইজ করার কোডটি দেখতে এমন হওয়া উচিত:

var settings = new JsonSerializerSettings(); 
settings.TypeNameHandling = TypeNameHandling.Objects;
var entity = JsonConvert.DeserializeObject<EntityType>(json, settings);

TypeNameHandlingপতাকা ব্যবহার করার সময় কোনও জেসন এভাবে রূপান্তরিত হয় :এখানে চিত্র বর্ণনা লিখুন


-5

আমি এই একই জিনিসটি অবাক করেছি, তবে আমি ভয় করি যে এটি করা সম্ভব নয়।

আসুন এটি এইভাবে দেখুন। আপনি JSon.net এর কাছে ডেটা স্ট্রিং, এবং ডিজিটালাইজ করার জন্য টাইপ করেছেন। JSON.net যখন এটি হিট হয় তখন কী করতে হবে? এটি নতুন ধরণের আইসমোমিং তৈরি করতে পারে না কারণ আইসোমথিং কোনও বস্তু নয়। এটি আইসোমিং কার্যকর করে এমন একটি বস্তুও তৈরি করতে পারে না, যেহেতু এটি ব্যবহার করা উচিত ইসমোনিংয়ের উত্তরাধিকারী হতে পারে এমন অনেকগুলি বস্তুর মধ্যে কোনটির কোনও ক্লু নেই। ইন্টারফেসগুলি এমন একটি জিনিস যা স্বয়ংক্রিয়ভাবে সিরিয়ালাইজড হতে পারে তবে স্বয়ংক্রিয়ভাবে ডিসিরিয়ালাইজড হয় না।

আমি যা করব তা হ'ল আইসোমিংথকে বেস ক্লাসের সাথে প্রতিস্থাপন করা। এটি ব্যবহার করে আপনি যে প্রভাবটি সন্ধান করছেন তা পেতে সক্ষম হতে পারেন।


4
আমি বুঝতে পারি যে এটি "বাক্সের বাইরে" কাজ করবে না। তবে আমি ভাবছিলাম যে "[জসনপ্রপার্টি (টাইপফ (সামথিংবেস))]" এর মতো কিছু বৈশিষ্ট্য রয়েছে যা আমি একটি কংক্রিট শ্রেণি সরবরাহের জন্য ব্যবহার করতে পারি।
dthrasher

তাহলে উপরের কোডটিতে আইসমোটিংয়ের পরিবর্তে সামথিংবেস ব্যবহার করবেন না কেন? এটি যুক্তিযুক্ত হতে পারে যে আমরা এটিকে ভুল উপায়েও দেখছি কারণ সিরিয়ালকরণে ইন্টারফেসগুলি ব্যবহার করা উচিত নয়, যেহেতু তারা প্রদত্ত শ্রেণীর সাথে যোগাযোগের "ইন্টারফেস" কেবল সংজ্ঞায়িত করে। প্রযুক্তিগতভাবে কোনও ইন্টারফেসকে সিরিয়াল করা বাজে কথা, যেমন একটি বিমূর্ত ক্লাসিকে সিরিয়ালাইজ করা হয়। সুতরাং এটি "সম্পন্ন" হওয়ার সময় আমি যুক্তি দিয়েছিলাম যে এটি "করা উচিত নয়"।
টিমোথি বাল্ড্রিজ

আপনি কি নিউটনসফট.জসন.সরিয়ালাইজেশন নেমস্পেসের কোনও ক্লাসের দিকে নজর রেখেছেন? বিশেষত JsonObjectContract ক্লাস?
জনি

-9

এখানে স্কটগু রচিত একটি নিবন্ধের উল্লেখ রয়েছে

তার উপর ভিত্তি করে, আমি কিছু কোড লিখেছিলাম যা আমি মনে করি সহায়ক হতে পারে

public interface IEducationalInstitute
{
    string Name
    {
        get; set;
    }

}

public class School : IEducationalInstitute
{
    private string name;
    #region IEducationalInstitute Members

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    #endregion
}

public class Student 
{
    public IEducationalInstitute LocalSchool { get; set; }

    public int ID { get; set; }
}

public static class JSONHelper
{
    public static string ToJSON(this object obj)
    {
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        return serializer.Serialize(obj);
    }
    public  static string ToJSON(this object obj, int depth)
    {
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        serializer.RecursionLimit = depth;
        return serializer.Serialize(obj);
    }
}

এবং এইভাবে আপনি এটি কল হবে

School myFavSchool = new School() { Name = "JFK High School" };
Student sam = new Student()
{
    ID = 1,
    LocalSchool = myFavSchool
};
string jSONstring = sam.ToJSON();

Console.WriteLine(jSONstring);
//Result {"LocalSchool":{"Name":"JFK High School"},"ID":1}

যদি আমি এটি সঠিকভাবে বুঝতে পারি, তবে আমি মনে করি না যে আপনাকে একটি কংক্রিট শ্রেণি নির্দিষ্ট করতে হবে যা জেএসএন সিরিয়ালাইজেশনের জন্য ইন্টারফেস প্রয়োগ করে।


4
আপনার নমুনা জাভাস্ক্রিপ্টসিরাইজার ব্যবহার করে,। নেট ফ্রেমওয়ার্কের একটি শ্রেণি। আমি আমার সিরিয়ালাইজার হিসাবে জসন.এনইটি ব্যবহার করছি। কোডেপ্লেক্স
dthrasher

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