C# Присвояване на свойство по подразбиране за клас и оператор =

Проблем 1:

Имам просто приложение winforms и искам да обвържа DataBind моето свойство Person.Name към текстово поле. Името е от тип StringField. Първоначално дефинирах свойството Name като String. Свързването на данни работи чудесно за типове стойности като String. Бих искал свойството StringField.Value да бъде свойството по подразбиране на StringField. Искам да видя стойността на StringField.Value в текстовото поле, а не текста "FieldApp.StringField".

Проблем 2:

Бих искал да мога да присвоя низ към StringField с помощта на оператор =. Това присвояване ще доведе до задаване на член StringField.Value.

Може ли това да бъде постигнато?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace FieldApp
{
    public class StringField
    {
        public string Value { get; set; }    
    }

    public class Person
    {

        //private String _Name;
        //public String Name
        //{
        //    get { return _Name; }
        //    set { _Name = value; }
        //}

        //public Person(string name)
        //{
        //    Name = name;
        //}

        private StringField _Name;
        public StringField Name
        {
            get { return _Name; }
            set { _Name = value; }
        }

        public Person(string name)
        {
            Name = new StringField();
            Name.Value = name;
        }
    }

    public partial class FieldAppForm : Form
    {
        Person person = new Person("steve");

        public FieldAppForm()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //our form contains a button1 and textBox1

            //this compiles
            person.Name.Value = "steve";

            //this does not. Is there anyway to accomplish this?
            person.Name = "steve";

            //steve appears in the textbox 
            textBox1.DataBindings.Add("Text", person, "Name.Value");

            //FieldApp.StringField appears in the textbox 
            textBox1.DataBindings.Add("Text", person, "Name");
        }
    }
}

person Steve    schedule 11.01.2009    source източник


Отговори (5)


Можете да създадете имплицитно претоварване на оператора. След това можете да създадете StringField от низове като този:

StringField field = "value of new object";
string value=(string)field;

Знайте, че това създава нов StringField обект. Не бих ви посъветвал непременно да правите това.

[System.Diagnostics.DebuggerDisplay("{Value}")]
public class StringField
{
    public string Value { get; set; }
    public static implicit operator StringField(string s)
    {
        return new StringField { Value = s };
    }

    public static explicit operator string(StringField f)
    {
        return f.Value;
    }
    public override string ToString()
    {
        return Value;
    }
}
person Øyvind Skaar    schedule 11.01.2009

Относно обвързването на данни, за някои цели за обвързване (PropertyGrid, DataGridView и т.н.), можете да направите това с TypeConverter (вижте по-долу). За съжаление, това изглежда не работи с TextBox, така че мисля, че най-добрият ви вариант е просто да добавите свойство shim (както вече беше предложено):

string NameString
{
   get { return Name.Value; }
   set { Name.Value = value; } // or new blah...
}

(и се свързва с NameString)

В миналото съм използвал персонализирани PropertyDescriptor реализации, за да заобиколя това, но не си струва само за това.

Както и да е, пример за TypeConverter (работи с PropertyGrid и DataGridView):

[TypeConverter(typeof(StringFieldConverter))]
public class StringField
{
    public StringField() : this("") { }
    public StringField(string value) { Value = value; }
    public string Value { get; private set; }
}

class StringFieldConverter : TypeConverter
{
    public override bool CanConvertFrom(
        ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string)
            || base.CanConvertFrom(context, sourceType);
    }
    public override object ConvertFrom(
        ITypeDescriptorContext context,
        System.Globalization.CultureInfo culture,
        object value)
    {
        string s = value as string;
        if (s != null) return new StringField(s);
        return base.ConvertFrom(context, culture, value);
    }
    public override bool CanConvertTo(
        ITypeDescriptorContext context, Type destinationType)
    {
        return destinationType == typeof(string)
            || base.CanConvertTo(context, destinationType);
    }
    public override object ConvertTo(
        ITypeDescriptorContext context,
        System.Globalization.CultureInfo culture,
        object value, Type destinationType)
    {
        if (destinationType == typeof(string) && value != null
            && value is StringField)
        {
            return ((StringField)value).Value;
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }
}
person Marc Gravell    schedule 11.01.2009

Можете да реализирате присвояване, като предоставите оператор за преобразуване. Като се има предвид естеството на вашия клас, вие също трябва да замените методите на Object:

public class StringField {
  public string Value { get; set; }
  public static implicit operator StringField(string value) {
    StringField sf = new StringField();
    sf.Value = value;
    return sf;
  }
  public override string ToString() {
    return Value;
  }
  public override bool Equals(object obj) {
    if (obj == null || !(obj is StringField)) return false;
    return 0 == string.Compare(Value, (obj as StringField).Value);
  }
  public override int GetHashCode() {
    return Value.GetHashCode();
  }
}
person Hans Passant    schedule 11.01.2009

Можете да имате StringField, като картографирате свойството Name към полето Name.Value вътрешно във вашия клас.

така че можете да дефинирате свойството Name по следния начин:

string Name 
{
   get { return _name.Value; }
   set { _name.Value = value; }
}

Тук _name е вашата променлива StringField.

person Rune Grimstad    schedule 11.01.2009

Операторът за присвояване не може да бъде заменен в C#. Можете обаче да имате свойство, което да извърши преобразуването на типа вместо вас и да го изложи на класа

person Rowland Shaw    schedule 11.01.2009