সি # তে রেফারেন্স সহ সম্পত্তিগুলি পাস করা


224

আমি নিম্নলিখিতটি করার চেষ্টা করছি:

GetString(
    inputString,
    ref Client.WorkPhone)

private void GetString(string inValue, ref string outValue)
{
    if (!string.IsNullOrEmpty(inValue))
    {
        outValue = inValue;
    }
}

এটি আমাকে একটি সংকলন ত্রুটি দিচ্ছে। আমি মনে করি এটি অর্জন করার জন্য আমি কী চেষ্টা করছি তা খুব পরিষ্কার। মূলত আমি GetStringএকটি ইনপুট স্ট্রিংয়ের বিষয়বস্তু এর WorkPhoneসম্পত্তিতে অনুলিপি করতে চাই Client

রেফারেন্স দিয়ে কোনও সম্পত্তি পাস করা কি সম্ভব?


কেন, এই দেখুন stackoverflow.com/questions/564557/...
nawfal

উত্তর:


423

সম্পত্তি রেফারেন্স দ্বারা পাস করা যাবে না। এই সীমাবদ্ধতাটি ঘিরে কাজ করতে পারেন এমন কয়েকটি উপায়।

1. রিটার্ন মান

string GetString(string input, string output)
{
    if (!string.IsNullOrEmpty(input))
    {
        return input;
    }
    return output;
}

void Main()
{
    var person = new Person();
    person.Name = GetString("test", person.Name);
    Debug.Assert(person.Name == "test");
}

2. প্রতিনিধি

void GetString(string input, Action<string> setOutput)
{
    if (!string.IsNullOrEmpty(input))
    {
        setOutput(input);
    }
}

void Main()
{
    var person = new Person();
    GetString("test", value => person.Name = value);
    Debug.Assert(person.Name == "test");
}

3. লিনকিউ এক্সপ্রেশন

void GetString<T>(string input, T target, Expression<Func<T, string>> outExpr)
{
    if (!string.IsNullOrEmpty(input))
    {
        var expr = (MemberExpression) outExpr.Body;
        var prop = (PropertyInfo) expr.Member;
        prop.SetValue(target, input, null);
    }
}

void Main()
{
    var person = new Person();
    GetString("test", person, x => x.Name);
    Debug.Assert(person.Name == "test");
}

4. প্রতিবিম্ব

void GetString(string input, object target, string propertyName)
{
    if (!string.IsNullOrEmpty(input))
    {
        var prop = target.GetType().GetProperty(propertyName);
        prop.SetValue(target, input);
    }
}

void Main()
{
    var person = new Person();
    GetString("test", person, nameof(Person.Name));
    Debug.Assert(person.Name == "test");
}

2
উদাহরণ ভালবাসা। আমি দেখতে পেয়েছি যে এটি এক্সটেনশন পদ্ধতির জন্যও দুর্দান্ত জায়গা: codeপাবলিক স্ট্যাটিক স্ট্রিং গেটভ্যালুআরডিফল্ট (এই স্ট্রিং এর, স্ট্রিংটি নলস্ট্রিং) {যদি (s == নাল) {s = isNullString; } রিটার্ন এস; Main প্রধান অকার্যকর ()। person.MobilePhone.GetValueOrDefault (person.WorkPhone); }
ব্ল্যাকজ্যাককেট

9
সমাধান 2 এ, 2 য় প্যারামিটার getOutputঅপ্রয়োজনীয়।
জয়দার

31
এবং আমি মনে করি যে সমাধান 3 এর আরও ভাল নাম হ'ল প্রতিচ্ছবি।
জয়দার

1
সমাধান 2-এ, 2 য় প্যারামিটারের গেটআউটপুট অপ্রয়োজনীয় - সত্য তবে আমি এটি সেট করছিলাম যা মূল্য ছিল তা দেখার জন্য এটি getString এর অভ্যন্তরে ব্যবহার করেছি। এই প্যারামিটার ছাড়া এটি কীভাবে করবেন তা নিশ্চিত নন।
পেট্রাস

3
@ গনকোডিংগুডবাই: তবে সবচেয়ে কম দক্ষ পন্থা। কোনও সম্পত্তিকে কেবল মূল্য নির্ধারণ করার জন্য প্রতিবিম্ব ব্যবহার করা বাদামকে ফাটানোর জন্য স্লেজহ্যামার গ্রহণ করার মতো। এছাড়াও, এমন একটি পদ্ধতি GetStringযা সম্পত্তি নির্ধারণের কথা বলেছিল তা স্পষ্টভাবে ভুল নাম দেওয়া হয়েছে।
টিম শেমলেটার

27

সম্পত্তি নকল না করে

void Main()
{
    var client = new Client();
    NullSafeSet("test", s => client.Name = s);
    Debug.Assert(person.Name == "test");

    NullSafeSet("", s => client.Name = s);
    Debug.Assert(person.Name == "test");

    NullSafeSet(null, s => client.Name = s);
    Debug.Assert(person.Name == "test");
}

void NullSafeSet(string value, Action<string> setter)
{
    if (!string.IsNullOrEmpty(value))
    {
        setter(value);
    }
}

4
নাম পরিবর্তন জন্য +1 GetStringকরতে NullSafeSet, কারণ সাবেক কোন মানে এখানে তোলে।
ক্যামিলো মার্টিন

25

আমি এক্সপ্রেশনট্রি বৈকল্পিক এবং সি # 7 (যদি কারও আগ্রহ থাকে) ব্যবহার করে একটি মোড়ক লিখেছিলাম:

public class Accessor<T>
{
    private Action<T> Setter;
    private Func<T> Getter;

    public Accessor(Expression<Func<T>> expr)
    {
        var memberExpression = (MemberExpression)expr.Body;
        var instanceExpression = memberExpression.Expression;
        var parameter = Expression.Parameter(typeof(T));

        if (memberExpression.Member is PropertyInfo propertyInfo)
        {
            Setter = Expression.Lambda<Action<T>>(Expression.Call(instanceExpression, propertyInfo.GetSetMethod(), parameter), parameter).Compile();
            Getter = Expression.Lambda<Func<T>>(Expression.Call(instanceExpression, propertyInfo.GetGetMethod())).Compile();
        }
        else if (memberExpression.Member is FieldInfo fieldInfo)
        {
            Setter = Expression.Lambda<Action<T>>(Expression.Assign(memberExpression, parameter), parameter).Compile();
            Getter = Expression.Lambda<Func<T>>(Expression.Field(instanceExpression,fieldInfo)).Compile();
        }

    }

    public void Set(T value) => Setter(value);

    public T Get() => Getter();
}

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

var accessor = new Accessor<string>(() => myClient.WorkPhone);
accessor.Set("12345");
Assert.Equal(accessor.Get(), "12345");

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

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

5

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

GetString(
    inputString,
    (() => client.WorkPhone, x => client.WorkPhone = x))

void GetString(string inValue, (Func<string> get, Action<string> set) outValue)
{
    if (!string.IsNullOrEmpty(outValue))
    {
        outValue.set(inValue);
    }
}

3

আরেকটি কৌতুক এখনো উল্লেখ না শ্রেণী যেটি একটি সম্পত্তি প্রয়োগ আছে (যেমন Fooধরনের Bar) একটি প্রতিনিধি সংজ্ঞায়িত delegate void ActByRef<T1,T2>(ref T1 p1, ref T2 p2);এবং একটি পদ্ধতি বাস্তবায়ন ActOnFoo<TX1>(ref Bar it, ActByRef<Bar,TX1> proc, ref TX1 extraParam1)(এবং সম্ভবত পাশাপাশি দুই এবং তিন "অতিরিক্ত পরামিতি" জন্য সংস্করণ) যার অভ্যন্তরীণ উপস্থাপনা পাস হবে Fooথেকে একটি refপরামিতি হিসাবে সরবরাহিত পদ্ধতি । সম্পত্তি নিয়ে কাজ করার অন্যান্য পদ্ধতির তুলনায় এর কয়েকটি বড় সুবিধা রয়েছে:

  1. সম্পত্তি "স্থানে" আপডেট করা হয়; সম্পত্তি যদি এমন কোনও ধরণের হয় যা `ইন্টারলকড` পদ্ধতির সাথে সামঞ্জস্যপূর্ণ হয়, বা যদি এ জাতীয় ধরণের উদ্ভাসিত ক্ষেত্রগুলির সাথে কাঠামো হয় তবে `ইন্টারলকড` পদ্ধতিটি সম্পত্তির পারমাণবিক আপডেটগুলি সম্পাদন করতে ব্যবহৃত হতে পারে।
  2. সম্পত্তিটি যদি একটি উন্মুক্ত ক্ষেত্রের কাঠামো হয় তবে কাঠামোর ক্ষেত্রগুলি এর কোনও অপ্রয়োজনীয় অনুলিপি তৈরি না করেই সংশোধন করা যেতে পারে।
  3. যদি `অ্যাক্টবাইরাইফ পদ্ধতিটি সরবরাহকারী প্রতিনিধিটির কাছে তার কলার থেকে এক বা একাধিক` রেফারি পরামিতিগুলি অতিক্রম করে, তবে সিঙ্গলটন বা স্ট্যাটিক প্রতিনিধি ব্যবহার করা সম্ভব হবে, এভাবে রান-টাইমে ক্লোজার বা প্রতিনিধি তৈরির প্রয়োজনীয়তা এড়ানো সম্ভব নয়।
  4. সম্পত্তিটি কখন এটি "কাজ করা" হচ্ছে তা জানে। লক ধরে রাখার সময় বাহ্যিক কোড কার্যকর করার ক্ষেত্রে সতর্কতা অবলম্বন করা সর্বদা প্রয়োজনীয়, যদি কেউ কলারকে তাদের কলব্যাকে খুব বেশি কিছু না করার জন্য বিশ্বাস করতে পারে যার জন্য অন্য লকের প্রয়োজন হতে পারে তবে পদ্ধতিটি কোনও সম্পত্তি দিয়ে অ্যাক্সেসকে রক্ষা করা ব্যবহারিক হতে পারে লক, যেমন আপডেটগুলি which তুলনা-এক্সচেঞ্জ` এর সাথে সামঞ্জস্যপূর্ণ নয় তবুও আধা-পরমাণুভাবে সম্পাদন করা যেতে পারে।

জিনিসগুলি পাস refকরা একটি দুর্দান্ত প্যাটার্ন; খুব খারাপ এটি বেশি ব্যবহৃত হয় না।


3

নাথনের লিনক এক্সপ্রেশন সলিউশনের সামান্য বিস্তৃতি । মাল্টি জেনেরিক প্যারাম ব্যবহার করুন যাতে সম্পত্তি স্ট্রিংয়ের মধ্যে সীমাবদ্ধ না থাকে।

void GetString<TClass, TProperty>(string input, TClass outObj, Expression<Func<TClass, TProperty>> outExpr)
{
    if (!string.IsNullOrEmpty(input))
    {
        var expr = (MemberExpression) outExpr.Body;
        var prop = (PropertyInfo) expr.Member;
        if (!prop.GetValue(outObj).Equals(input))
        {
            prop.SetValue(outObj, input, null);
        }
    }
}

2

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


2

যদি সম্ভব না হয়. তুমি বলতে পার

Client.WorkPhone = GetString(inputString, Client.WorkPhone);

যেখানে WorkPhoneএকটি লিখনযোগ্য stringসম্পত্তি এবং এর সংজ্ঞা GetStringপরিবর্তিত হয়

private string GetString(string input, string current) { 
    if (!string.IsNullOrEmpty(input)) {
        return input;
    }
    return current;
}

এটিতে একই শব্দার্থক থাকবে যার জন্য আপনি চেষ্টা করছেন বলে মনে হচ্ছে।

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


1

আপনি যা করতে চেষ্টা করতে পারেন তা হ'ল সম্পত্তি মান ধরে রাখার জন্য একটি বিষয় তৈরি করা। এইভাবে আপনি বস্তুটি পাস করতে পারেন এবং তারপরেও অভ্যন্তরের সম্পত্তিটিতে অ্যাক্সেস থাকতে পারে।


1

সম্পত্তি রেফারেন্স দিয়ে পাস করা যাবে না? তারপরে এটি একটি ক্ষেত্র করুন, এবং সম্পত্তিটিকে জনসম্মুখে উল্লেখ করার জন্য এটি ব্যবহার করুন:

public class MyClass
{
    public class MyStuff
    {
        string foo { get; set; }
    }

    private ObservableCollection<MyStuff> _collection;

    public ObservableCollection<MyStuff> Items { get { return _collection; } }

    public MyClass()
    {
        _collection = new ObservableCollection<MyStuff>();
        this.LoadMyCollectionByRef<MyStuff>(ref _collection);
    }

    public void LoadMyCollectionByRef<T>(ref ObservableCollection<T> objects_collection)
    {
        // Load refered collection
    }
}

0

আপনি refকোনও সম্পত্তি করতে পারবেন না , তবে আপনার ফাংশনগুলির উভয় প্রয়োজন getএবং setঅ্যাক্সেসের প্রয়োজন হলে আপনি সংজ্ঞায়িত সম্পত্তি সহ কোনও শ্রেণীর উদাহরণ দিয়ে যেতে পারেন:

public class Property<T>
{
    public delegate T Get();
    public delegate void Set(T value);
    private Get get;
    private Set set;
    public T Value {
        get {
            return get();
        }
        set {
            set(value);
        }
    }
    public Property(Get get, Set set) {
        this.get = get;
        this.set = set;
    }
}

উদাহরণ:

class Client
{
    private string workPhone; // this could still be a public property if desired
    public readonly Property<string> WorkPhone; // this could be created outside Client if using a regular public property
    public int AreaCode { get; set; }
    public Client() {
        WorkPhone = new Property<string>(
            delegate () { return workPhone; },
            delegate (string value) { workPhone = value; });
    }
}
class Usage
{
    public void PrependAreaCode(Property<string> phone, int areaCode) {
        phone.Value = areaCode.ToString() + "-" + phone.Value;
    }
    public void PrepareClientInfo(Client client) {
        PrependAreaCode(client.WorkPhone, client.AreaCode);
    }
}

0

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

var phone = Client.WorkPhone;
GetString(input, ref phone);
Client.WorkPhone = phone;

0

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

https://github.com/dotnet/csharplang/issues/1235

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