সি # এর `notnull` প্রকারটিকে নালাগুলি তৈরি করতে পারে না


9

আমি মরিচা Resultবা হাস্কেলের মতো একটি ধরণের তৈরি করার চেষ্টা করছি Eitherএবং আমি এটি এখনও পেয়েছি:

public struct Result<TResult, TError>
    where TResult : notnull
    where TError : notnull
{
    private readonly OneOf<TResult, TError> Value;
    public Result(TResult result) => Value = result;
    public Result(TError error) => Value = error;

    public static implicit operator Result<TResult, TError>(TResult result)
        => new Result<TResult, TError>(result);

    public static implicit operator Result<TResult, TError>(TError error)
        => new Result<TResult, TError>(error);

    public void Deconstruct(out TResult? result, out TError? error)
    {
        result = (Value.IsT0) ? Value.AsT0 : (TResult?)null;
        error = (Value.IsT1) ? Value.AsT1 : (TError?)null;
    }  
}

প্রদত্ত যে উভয় প্রকারের প্যারামিটারগুলিই সীমাবদ্ধ রয়েছে notnull, কেন এটি অভিযোগ করা হচ্ছে (যে কোনও জায়গায় যেখানে এর ?পরেও চিহ্ন সহ একটি ধরণের প্যারামিটার রয়েছে ) যে:

একটি nullable টাইপ পরামিতি একটি মান টাইপ বা নন-অযোগ্য রেফারেন্স টাইপ হিসাবে জানা থাকতে হবে। একটি 'শ্রেণি', 'স্ট্রাক্ট' বা টাইপ সীমাবদ্ধতা যুক্ত করার বিষয়টি বিবেচনা করুন।

?


আমি সি # 8 এ .NET কোর 3 টি ব্যবহারযোগ্য অযোগ্য রেফারেন্স প্রকারগুলি সহ সক্ষম করব।


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

উত্তর:


12

মূলত আপনি এমন কিছু চাইছেন যা IL তে প্রতিনিধিত্ব করা যায় না। অণনযোগ্য মান ধরণের এবং অযোগ্য রেফারেন্স ধরণেরগুলি খুব ভিন্ন প্রাণী এবং এটি উত্স কোডে একইরকম দেখায়, আইএলটি খুব আলাদা different একটি মান ধরনের nullable সংস্করণ Tএকটি ভিন্ন প্রকার (হয় Nullable<T>) একটি রেফারেন্স ধরনের nullable সংস্করণ যেহেতু Tহয় একই টাইপ বৈশিষ্ট্যাবলী কম্পাইলার কি আশা কহন সঙ্গে।

এই সহজ উদাহরণ বিবেচনা করুন:

public class Foo<T> where T : notnull
{
    public T? GetNullValue() => 
}

এটি একই কারণে অবৈধ।

যদি আমরা Tস্ট্রাক্ট হতে বাধ্য হই তবে GetNullValueপদ্ধতির জন্য উত্পন্ন আইএলটির একটি রিটার্ন টাইপ থাকবে Nullable<T>

যদি আমরা Tএকটি অ-অযোগ্য রেফারেন্স ধরণের হতে বাধ্য হই, তবে GetNullValueপদ্ধতির জন্য উত্পন্ন Tআইএলটির একটি রিটার্নের ধরণ থাকবে তবে নালিয়াযোগ্যতার দিকের জন্য একটি বৈশিষ্ট্য সহ।

সংকলকটি এমন পদ্ধতির জন্য আইএল তৈরি করতে পারে না যার রিটার্ন টাইপ উভয় Tএবং Nullable<T>একই সাথে রয়েছে।

এটি মূলত সমস্ত সিএলআর ধারণাটি নয় এমন রেফারেন্স রেফারেন্সের ফলাফল যা কোডের উদ্দেশ্যে অভিপ্রায় প্রকাশ করতে এবং সংকলক-সময়ে কিছু পরীক্ষা করার জন্য সংকলকটি পেতে সহায়তা করার জন্য এটি কেবল যাদুঘর সংকলক iler

ত্রুটির বার্তাটি যতটা পরিষ্কার হতে পারে তেমন পরিষ্কার নয়। T"একটি মান ধরণের বা অ-শর্তযুক্ত রেফারেন্স টাইপ" হিসাবে পরিচিত। আরও সুনির্দিষ্ট (তবে উল্লেখযোগ্যভাবে শব্দযুক্ত) ত্রুটি বার্তাটি হ'ল:

একটি nullable টাইপ পরামিতি একটি মান টাইপ হিসাবে পরিচিত হতে হবে, বা একটি নন-অযোগ্য রেফারেন্স টাইপ হিসাবে পরিচিত। একটি 'শ্রেণি', 'স্ট্রাক্ট' বা টাইপ সীমাবদ্ধতা যুক্ত করার বিষয়টি বিবেচনা করুন।

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


রানটাইম-ম্যাজিকও রয়েছে - আইএল-তে এই বিধিনিষেধকে উপস্থাপন করার কোনও উপায় না থাকা সত্ত্বেও আপনি কোনও স্থিতিস্থাপককে ছোট করতে পারবেন না। Nullable<T>একটি বিশেষ ধরণের যা আপনি নিজেকে তৈরি করতে পারবেন না। এবং তারপরে বোনাস পয়েন্ট রয়েছে যে কীভাবে মুছে ফেলা যায় তা দিয়ে বক্সিং করা হয়।
লুয়ান

1
@ লুয়ান: অণনীয় মান ধরণের জন্য রানটাইম যাদু রয়েছে, তবে অযোগ্য রেফারেন্স ধরণের জন্য নয়।
জন স্কিটি

6

সাবধানবাণী জন্য কারণ বিভাগে ব্যাখ্যা করা হয় The issue with T?এর বাইরে Nullable রেফারেন্স প্রকারভেদ চেষ্টা । দীর্ঘ গল্প সংক্ষিপ্ত, আপনি যদি ব্যবহার করেন তবে আপনাকে T?টাইপটি শ্রেণি বা কাঠামো কিনা তা নির্দিষ্ট করতে হবে। আপনি প্রতিটি ক্ষেত্রে দুটি ধরণের তৈরি শেষ করতে পারেন।

গভীর সমস্যাটি হ'ল রেজাল্ট বাস্তবায়ন করতে এবং সাফল্য এবং ত্রুটি উভয় মান উভয়কে ধরে রাখতে এক ধরণের ব্যবহারের ফলে রেজাল্টটি ঠিক করার মতো সমস্যা এবং আরও কয়েকটি সমস্যা ফিরে আসে।

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

এফ # তে ফলাফল (এবং হয়)

প্রারম্ভিক পয়েন্টটি এফ # এর ফলাফলের ধরণের এবং বৈষম্যমূলক ইউনিয়ন হওয়া উচিত । সর্বোপরি, এটি ইতিমধ্যে .NET এ কাজ করে।

F # এ ফলাফলের ধরণটি হ'ল:

type Result<'T,'TError> =
    | Ok of ResultValue:'T
    | Error of ErrorValue:'TError

প্রকারগুলি নিজেরাই কেবল যা প্রয়োজন তা বহন করে।

এফ # এর Uাবিগুলি শূন্যের প্রয়োজন ছাড়াই নিখুঁত প্যাটার্ন মেলানোর অনুমতি দেয়:

match res2 with
| Ok req -> printfn "My request was valid! Name: %s Email %s" req.Name req.Email
| Error e -> printfn "Error: %s" e

এটি সি # 8 এ অনুকরণ করে

দুর্ভাগ্যক্রমে, সি # 8 এর এখনও Dাবি নেই, সেগুলি সি # 9 এর জন্য নির্ধারিত হয়েছে সি সি 8-তে আমরা এটি অনুকরণ করতে পারি, তবে আমরা সম্পূর্ণ মিল খুঁজে পাই:

#nullable enable

public interface IResult<TResult,TError>{}​

struct Success<TResult,TError> : IResult<TResult,TError>
{
    public TResult Value {get;}

    public Success(TResult value)=>Value=value;

    public void Deconstruct(out TResult value)=>value=Value;        
}

struct Error<TResult,TError> : IResult<TResult,TError>
{
    public TError ErrorValue {get;}

    public Error(TError error)=>ErrorValue=error;

    public void Deconstruct(out TError error)=>error=ErrorValue;
}

এবং এটি ব্যবহার করুন:

IResult<double,string> Sqrt(IResult<double,string> input)
{
    return input switch {
        Error<double,string> e => e,
        Success<double,string> (var v) when v<0 => new Error<double,string>("Negative"),
        Success<double,string> (var v)  => new Success<double,string>(Math.Sqrt(v)),
        _ => throw new ArgumentException()
    };
}

সম্পূর্ণ প্যাটার্ন মেলানো ছাড়াই সংকলক সতর্কতা এড়ানোর জন্য আমাদের সেই ডিফল্ট ধারাটি যুক্ত করতে হবে।

আমি এখনও মৃত মূল্যবোধগুলি প্রবর্তন না করে পুরোপুরি ম্যাচিংয়ের একটি উপায় খুঁজছি , যদিও সেগুলি কেবল একটি বিকল্প are

অপশন / হয়তো

বিস্তৃত মেলানো ব্যবহার করে এমন একটি বিকল্প ক্লাস তৈরি করা সহজ:

readonly struct Option<T> 
{
    public readonly T Value {get;}

    public readonly bool IsSome {get;}
    public readonly bool IsNone =>!IsSome;

    public Option(T value)=>(Value,IsSome)=(value,true);    

    public void Deconstruct(out T value,out bool isSome)=>(value,isSome)=(Value,IsSome);
}

//Convenience methods, similar to F#'s Option module
static class Option
{
    public static Option<T> Some<T>(T value)=>new Option<T>(value);    
    public static Option<T> None<T>()=>default;
}

যা এর সাথে ব্যবহার করা যেতে পারে:

string cateGory = someValue switch { Option<Category> (_    ,false) =>"No Category",
                                     Option<Category> (var v,true)  => v.Name
                                   };
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.