জেএসএন.এন.এফ: ডিফল্ট কনস্ট্রাক্টর ব্যবহার না করে ডিসরিয়ালাইজ করবেন কীভাবে?


136

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

আমার সমস্যা: আমি যদি ডিফল্ট কনস্ট্রাক্টর অপসারণ করি এবং JSON স্ট্রিংয়ে পাস করি তবে অবজেক্টটি সঠিকভাবে ডিসরিয়ালাইজ করে এবং কোনও সমস্যা ছাড়াই কনস্ট্রাক্টর প্যারামিটারে পাস করে। আমি প্রত্যাশা করে যেভাবে প্রত্যাশিত জিনিসটি ফিরে পেয়েছি। যাইহোক, আমি যখন অবজেক্টটিতে ডিফল্ট কনস্ট্রাক্টর যুক্ত করব তখনই আমি যখন JsonConvert.DeserializeObject<Result>(jsontext)বৈশিষ্ট্যগুলি কল করি তখন আর জনবসতি হয় না।

এই মুহুর্তে আমি new JsonSerializerSettings(){CheckAdditionalContent = true}deserialization কল যোগ করার চেষ্টা করেছি । যে কিছুই করেনি।

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

আমার নির্মাতাদের একটি নমুনা এখানে:

public Result() { }

public Result(int? code, string format, Dictionary<string, string> details = null)
{
    Code = code ?? ERROR_CODE;
    Format = format;

    if (details == null)
        Details = new Dictionary<string, string>();
    else
        Details = details;
}

হয়তো এই করতে পারেন সাহায্যের stackoverflow.com/questions/8254503/...
csharpwinphonexaml

ডুপ:
জসন

উত্তর:


208

জসন.নেট যদি কোনও বস্তুতে ডিফল্ট (প্যারামিটারলেস) কনস্ট্রাক্টর ব্যবহার করতে পছন্দ করে। যদি সেখানে একাধিক কনস্ট্রাক্টর থাকে এবং আপনি Json.Net কোনও অ-ডিফল্ট ব্যবহার করতে চান, তবে আপনি [JsonConstructor]যে কনস্ট্রাক্টরকে Json.Net কল করতে চান তাতে আপনি সেই বৈশিষ্ট্যটি যুক্ত করতে পারেন ।

[JsonConstructor]
public Result(int? code, string format, Dictionary<string, string> details = null)
{
    ...
}

এটি সঠিকভাবে কাজ করার জন্য কনস্ট্রাক্টর প্যারামিটারের নামগুলি JSON অবজেক্টের (সম্পর্কিত বিষয়টিকে উপেক্ষা করে) সম্পর্কিত সম্পত্তি সম্পর্কিত নামগুলির সাথে মিলে যায়। তবে আপনার প্রয়োজনবস্তুটির প্রতিটি সম্পত্তির জন্য কনস্ট্রাক্টর প্যারামিটার রাখার দরকার নেই। যে সমস্ত JSON অবজেক্ট বৈশিষ্ট্য যা কনস্ট্রাক্টর প্যারামিটারগুলি দ্বারা আচ্ছাদিত নয়, তাদের জন্য Json.Net সর্বজনীন সম্পত্তি অ্যাক্সেসরগুলি (বা বৈশিষ্ট্যগুলি / চিহ্নিত ক্ষেত্রগুলি [JsonProperty]) এটি নির্মাণের পরে পপুলেট করার জন্য চেষ্টা করবে।

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

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // Load the JSON for the Result into a JObject
        JObject jo = JObject.Load(reader);

        // Read the properties which will be used as constructor parameters
        int? code = (int?)jo["Code"];
        string format = (string)jo["Format"];

        // Construct the Result object using the non-default constructor
        Result result = new Result(code, format);

        // (If anything else needs to be populated on the result object, do that here)

        // Return the result
        return result;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

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

তারপরে, আপনার সিরিয়ালাইজার সেটিংসে রূপান্তরকারী যুক্ত করুন, এবং যখন আপনি ডিসিরিয়ালাইজ করবেন তখন সেটিংসটি ব্যবহার করুন:

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new ResultConverter());
Result result = JsonConvert.DeserializeObject<Result>(jsontext, settings);

4
এটি কাজ করে। এই ধরনের স্তন্যপান করে যে আমাকে এখন আমার মডেলগুলির প্রকল্পে JSON.net নির্ভরতা নিতে হবে, তবে আরে কী। আমি এটি উত্তর হিসাবে চিহ্নিত করব।
কুমাকডোনাল্ড

3
অন্যান্য বিকল্প রয়েছে - আপনি JsonConverterনিজের শ্রেণীর জন্য একটি কাস্টম তৈরি করতে পারেন । এটি নির্ভরতা সরিয়ে ফেলবে, তবে তারপরে আপনাকে কনভার্টারে নিজেকে ইনস্ট্যান্টিয়েটিং এবং পপুলিং পরিচালনা করতে হবে। এটি এমন একটি কাস্টম ContractResolverলিখতেও পারে যা জাসন.নেটকে অন্য কন্সট্রাক্টর পরিবর্তন করে এটি ব্যবহার করার নির্দেশ দেয় JsonObjectContractতবে এটি এটি শোনার চেয়ে কিছুটা কৌশলযুক্ত প্রমাণ করতে পারে।
ব্রায়ান রজার্স

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

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

1
ভুলে যাবেন নাusing Newtonsoft.Json;
ব্রুনো বিয়েরি

36

কিছুটা দেরি হয়ে গেছে এবং ঠিক এখানে উপযুক্ত নয়, তবে আমি এখানে আমার সমাধান যুক্ত করব, কারণ আমার প্রশ্নটির এটির সদৃশ হিসাবে বন্ধ হয়ে গিয়েছিল, এবং কারণ এই সমাধানটি সম্পূর্ণ আলাদা।

আমার Json.NETব্যবহারকারীর সংজ্ঞায়িত স্ট্রাক্ট ধরণের জন্য সুনির্দিষ্ট নির্দিষ্ট কন্সট্রাক্টরকে প্রাধান্য দেওয়ার জন্য একটি সাধারণ উপায়ের প্রয়োজন ছিল , তাই আমি সেই JsonConstructorবৈশিষ্ট্যগুলি বাদ দিতে পারি যা প্রকল্পের উপর নির্ভরশীলতা যুক্ত করতে পারে যেখানে প্রতিটি স্ট্রাক্ট সংজ্ঞায়িত হয়।

আমি কিছুটা বিপরীত হয়েছি এবং একটি কাস্টম চুক্তি সমাধানকারী কার্যকর করেছি যেখানে আমি CreateObjectContractআমার কাস্টম তৈরি যুক্তি যুক্ত করার পদ্ধতিটি ওভাররাইড করেছি ।

public class CustomContractResolver : DefaultContractResolver {

    protected override JsonObjectContract CreateObjectContract(Type objectType)
    {
        var c = base.CreateObjectContract(objectType);
        if (!IsCustomStruct(objectType)) return c;

        IList<ConstructorInfo> list = objectType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).OrderBy(e => e.GetParameters().Length).ToList();
        var mostSpecific = list.LastOrDefault();
        if (mostSpecific != null)
        {
            c.OverrideCreator = CreateParameterizedConstructor(mostSpecific);
            c.CreatorParameters.AddRange(CreateConstructorParameters(mostSpecific, c.Properties));
        }

        return c;
    }

    protected virtual bool IsCustomStruct(Type objectType)
    {
        return objectType.IsValueType && !objectType.IsPrimitive && !objectType.IsEnum && !objectType.Namespace.IsNullOrEmpty() && !objectType.Namespace.StartsWith("System.");
    }

    private ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method)
    {
        method.ThrowIfNull("method");
        var c = method as ConstructorInfo;
        if (c != null)
            return a => c.Invoke(a);
        return a => method.Invoke(null, a);
    }
}

আমি এটি এভাবে ব্যবহার করছি।

public struct Test {
  public readonly int A;
  public readonly string B;

  public Test(int a, string b) {
    A = a;
    B = b;
  }
}

var json = JsonConvert.SerializeObject(new Test(1, "Test"), new JsonSerializerSettings {
  ContractResolver = new CustomContractResolver()
});
var t = JsonConvert.DeserializeObject<Test>(json);
t.A.ShouldEqual(1);
t.B.ShouldEqual("Test");

2
আমি বর্তমানে উপরে গৃহীত উত্তরটি ব্যবহার করছি, তবে আপনার সমাধানটিও দেখানোর জন্য আপনাকে ধন্যবাদ জানাতে চাই!
ডটবার্ট

1
আমি স্ট্র্টের উপরের নিষেধাজ্ঞাকে সরিয়েছি (চেক করুন objectType.IsValueType) এবং এটি দুর্দান্ত কাজ করে, ধন্যবাদ!
অ্যালেক্স আঙ্গাস

@ অ্যালেক্সআঙ্গাস হ্যাঁ এই কৌশলটি সাধারণভাবে প্রয়োগ করা আপনার মতামতের জন্য আপনাকে ধন্যবাদ জানাতে পারে না।
জোল্টন

3

এখানে কয়েকটি উত্তরের উপর ভিত্তি করে, আমি CustomConstructorResolverএকটি বর্তমান প্রকল্পে ব্যবহারের জন্য একটি লিখেছি এবং আমি ভেবেছিলাম এটি সম্ভবত অন্য কাউকে সাহায্য করবে।

এটি নীচের রেজোলিউশন প্রক্রিয়াগুলি সমর্থন করে, সমস্ত কনফিগারযোগ্য:

  • একটি একক বেসরকারী কনস্ট্রাক্টর নির্বাচন করুন যাতে আপনি কোনও একটি বৈশিষ্ট্য দিয়ে চিহ্নিত না করেই কোনও ব্যক্তিগত নির্মাণকারীর সংজ্ঞা দিতে পারেন।
  • সর্বাধিক সুনির্দিষ্ট বেসরকারী নির্মাতা নির্বাচন করুন যাতে আপনি গুণাবলী ব্যবহার না করেই একাধিক ওভারলোড করতে পারেন।
  • ডিফল্ট রেজলভারের মতো - কোনও নির্দিষ্ট নামের একটি বৈশিষ্ট্যের সাথে চিহ্নিত কন্সট্রাক্টর নির্বাচন করুন, তবে জসন.নেট প্যাকেজের উপর নির্ভরতা ছাড়াই আপনার রেফারেন্স দরকার Newtonsoft.Json.JsonConstructorAttribute
public class CustomConstructorResolver : DefaultContractResolver
{
    public string ConstructorAttributeName { get; set; } = "JsonConstructorAttribute";
    public bool IgnoreAttributeConstructor { get; set; } = false;
    public bool IgnoreSinglePrivateConstructor { get; set; } = false;
    public bool IgnoreMostSpecificConstructor { get; set; } = false;

    protected override JsonObjectContract CreateObjectContract(Type objectType)
    {
        var contract = base.CreateObjectContract(objectType);

        // Use default contract for non-object types.
        if (objectType.IsPrimitive || objectType.IsEnum) return contract;

        // Look for constructor with attribute first, then single private, then most specific.
        var overrideConstructor = 
               (this.IgnoreAttributeConstructor ? null : GetAttributeConstructor(objectType)) 
            ?? (this.IgnoreSinglePrivateConstructor ? null : GetSinglePrivateConstructor(objectType)) 
            ?? (this.IgnoreMostSpecificConstructor ? null : GetMostSpecificConstructor(objectType));

        // Set override constructor if found, otherwise use default contract.
        if (overrideConstructor != null)
        {
            SetOverrideCreator(contract, overrideConstructor);
        }

        return contract;
    }

    private void SetOverrideCreator(JsonObjectContract contract, ConstructorInfo attributeConstructor)
    {
        contract.OverrideCreator = CreateParameterizedConstructor(attributeConstructor);
        contract.CreatorParameters.Clear();
        foreach (var constructorParameter in base.CreateConstructorParameters(attributeConstructor, contract.Properties))
        {
            contract.CreatorParameters.Add(constructorParameter);
        }
    }

    private ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method)
    {
        var c = method as ConstructorInfo;
        if (c != null)
            return a => c.Invoke(a);
        return a => method.Invoke(null, a);
    }

    protected virtual ConstructorInfo GetAttributeConstructor(Type objectType)
    {
        var constructors = objectType
            .GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
            .Where(c => c.GetCustomAttributes().Any(a => a.GetType().Name == this.ConstructorAttributeName)).ToList();

        if (constructors.Count == 1) return constructors[0];
        if (constructors.Count > 1)
            throw new JsonException($"Multiple constructors with a {this.ConstructorAttributeName}.");

        return null;
    }

    protected virtual ConstructorInfo GetSinglePrivateConstructor(Type objectType)
    {
        var constructors = objectType
            .GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);

        return constructors.Length == 1 ? constructors[0] : null;
    }

    protected virtual ConstructorInfo GetMostSpecificConstructor(Type objectType)
    {
        var constructors = objectType
            .GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
            .OrderBy(e => e.GetParameters().Length);

        var mostSpecific = constructors.LastOrDefault();
        return mostSpecific;
    }
}

গিস্ট হিসাবে এক্সএমএল ডকুমেন্টেশন সহ সম্পূর্ণ সংস্করণটি এখানে: https://gist.github.com/maverickelementalch/80f77f4b6bdce3b434b0f7a1d06baa95

প্রতিক্রিয়া প্রশংসা।


দুর্দান্ত সমাধান! ভাগ করে নেওয়ার জন্য ধন্যবাদ.
থোমাই

1

নিউটনসফট.জসনের ডিফল্ট আচরণটি নির্মাতাদের সন্ধান করতে চলেছে public। আপনার ডিফল্ট কন্সট্রাকটর শুধুমাত্র বর্গ বা একই সমাবেশ ধারণকারী ব্যবহৃত হয়, তাহলে, আপনি অ্যাক্সেস স্তর কমে যায় protectedবা internalযাতে Newtonsoft.Json আপনার পছন্দসই তুলে নেব publicকন্সট্রাকটর।

স্বীকার করা, এই সমাধানটি নির্দিষ্ট ক্ষেত্রে খুব সীমাবদ্ধ।

internal Result() { }

public Result(int? code, string format, Dictionary<string, string> details = null)
{
    Code = code ?? ERROR_CODE;
    Format = format;

    if (details == null)
        Details = new Dictionary<string, string>();
    else
        Details = details;
}

-1

সমাধান:

public Response Get(string jsonData) {
    var json = JsonConvert.DeserializeObject<modelname>(jsonData);
    var data = StoredProcedure.procedureName(json.Parameter, json.Parameter, json.Parameter, json.Parameter);
    return data;
}

মডেল:

public class modelname {
    public long parameter{ get; set; }
    public int parameter{ get; set; }
    public int parameter{ get; set; }
    public string parameter{ get; set; }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.