C#模拟重写赋值运算符(=)

C#模拟重写赋值运算符(=),c#,operator-overloading,variable-assignment,C#,Operator Overloading,Variable Assignment,我有一个有点简单的包装器类,有点问题 它看起来像这样: public class Wrapper<T> { private T _value; public Wrapper<T>(T value) { _value = value; } public static implicit operator Wrapper<T>(T value) { return new Wrapper<T>(value);

我有一个有点简单的包装器类,有点问题

它看起来像这样:

public class Wrapper<T>
{
  private T _value;

  public Wrapper<T>(T value)
  {
    _value = value;
  }

  public static implicit operator Wrapper<T>(T value)
  {
    return new Wrapper<T>(value);
  }

  public static implicit operator T(Wrapper<T> value)
  {
    return value._value;
  }
}
公共类包装器
{
私人T_值;
公共包装器(T值)
{
_价值=价值;
}
公共静态隐式运算符包装器(T值)
{
返回新包装(值);
}
公共静态隐式运算符T(包装器值)
{
返回值。\u值;
}
}
我已经重写了从和到T的隐式转换器,所以它的行为几乎就像T本身的一个实例

e、 g

Wrapper foo=42;
然而,在将包装器的一个实例分配给另一个实例时,我遇到了一个小问题,因为我只想分配第二个包装器类的值

所以现在,我必须这样做:

Wrapper<int> foo = 42;
Wrapper<int> bar = (int)foo;
Wrapper foo=42;
包装条=(int)foo;
或者通过属性公开_值

然而,由于这是在一个库中,我不希望用户依赖于记住这一点,你们知道我如何模拟重写赋值运算符吗

仅仅更改指针(就像将一个类实例分配给另一个类实例时那样)的问题是,我有一个指向这些包装器对象的指针字典,所以我不能让它们一直更改,因为字典会停止匹配

我可以看出这是否有点让人困惑,因此如果我遗漏了任何重要的内容,请随时提问:-)

如果您查看Nullable…它的功能与您在这里所做的非常类似,它使用.value属性公开内部值

仅仅更改指针(就像将一个类实例分配给另一个类实例时那样)的问题是,我有一个指向这些包装器对象的指针字典,所以我不能让它们一直更改,因为字典会停止匹配


我不确定我是否明白了,你到底在字典里储存了什么?因为如果您正在存储引用,CLR将根据需要更新它们。

您可以将包装器设置为
结构。但是,我不确定这是否适合您的应用程序设计。

由于赋值运算符不能重载,因此没有真正好的解决方案。正如其他人所指出的,使用结构将为您提供所需的赋值语义,但随后您将面临值语义——这通常不是一件好事

一个选项是重载构造函数:

public Wrapper(Wrapper<T> w)
{
    _value = w._value;
}

你可以很有创意,让一些操作员超负荷工作,让它什么都不做。不过,我不建议这样做。对这些类型的东西使用操作符重载通常会使代码变得神秘,并且经常中断。

这就是属性的用途。它们允许您定义任务的含义。您不能为类或结构本身定义它,因为它们已经由语言定义以执行必要的操作。只需将
属性添加到类中


或者,编辑您的问题,以更广泛地描述您的设计以及该包装器如何融入其中,因为有人可能会建议一种更简单的方法。

我刚刚研究了一下,将类设为结构实际上不是一个选项,因为它在无参数构造函数中有一些逻辑,而且它继承了一个抽象类,它包含内部抽象函数

我不能使用接口,因为那样会使这些函数公开,这会完全破坏逻辑

如果有帮助的话,我可以发布整个课程,但是有点长(130行) 或者我可以在一个单独的服务器上掷硬币,如果那样更好的话?(尽管这会损害这个问题的完整性,因为我最终可能会将其从该服务器上删除)

另外,如果不写一篇完整的文章,解释这门课真的很难:-/

不管怎样,我会试图说明我遇到的问题

假设有两个表类:CustomerTable和UserTable:

public class CustomerTable
{
  Wrapper<string> Name;
}

public class UserTable
{
  Wrapper<string> Name;
}
为了使其工作,开发人员应该做的是:

user.Name = (string)customer.Name;
然而,问题是,在编写代码时,头脑正常的人会想到这一点吗

即使我使用了Value属性,开发人员也必须记住编写

user.Name = customer.Name.Value; // or user.Name.Value = ....
开发人员可能会再次忘记这一点,然后突然出现异常或更糟的情况:数据没有持久化到数据库中

所以我的问题是,我希望包装器是完全透明的(它应该是可用的,就好像它实际上是它所包装的类/原语一样)。 然而,当从一个包装器分配到另一个包装器时,我的内部逻辑中断了


呸,写了很多东西,还有很多代码——如果我写得太多了,请告诉我。

不要隐式地将包装器双向转换

public class DBValue<T>
{
    public static implicit operator DBValue <T>(T value)
    {
         return new DBValue<T>(value);
    }

    public static explicit operator T(DBValue <T> dbValue)
    {
         return dbValue.Value;
    }

    private readonly T _value;
    public T Value { get { this._value; } }

    public DBValue(T value)
    {
         this._value = value;
    }
}

而不是

string value = MyProperty
…并不是那么繁重,而是确保每个人都知道到底发生了什么

编辑:


要真正回答这个问题,你不能覆盖引用赋值,或者让它看起来像你已经做过的那样,但是你不应该真的需要这样做。

A J Lane我明白你的意思,我想你是对的,我只是想让使用库尽可能简单

将DbValue隐式转换为T的原因是为了简单地转换期望T的函数

比如说

literalSomething.Text = Server.HtmlEncode(SomeTable.SomeStringColumn);
而不是

literalSomething.Text = Server.HtmlEncode((string)SomeTable.SomeStringColumn);
这要求强制转换是隐式的

话虽如此,我只是在打字时读了你的评论,我可以看出这正是问题所在

我想我会回到通过属性公开价值上来,它只需要开发人员输入更多的内容,我想这会让代码变得丑陋

想象一下DbValue:

if (someValue.Value.HasValue) // someValue is DbValue<int?>
if(someValue.Value.HasValue)//someValue是DbValue
但是,同样地,使用“丑陋”的代码可能比仅仅通过阅读它而表现出不同于预期的行为的代码要好

我想这个问题最终会成为一个“最佳实践”问题

最后,我将创建一个Value属性并使用它而不是implic
string value = MyProperty.Value
string value = (string)MyProperty
string value = MyProperty
literalSomething.Text = Server.HtmlEncode(SomeTable.SomeStringColumn);
literalSomething.Text = Server.HtmlEncode((string)SomeTable.SomeStringColumn);
if (someValue.Value.HasValue) // someValue is DbValue<int?>
public class CustomerTable
{
    private Wrapper<string> _Name;
    public Wrapper<string> Name {
        get { return _Name; }
        set { _Name = (string)value; }
    }
}

public class UserTable
{
    private Wrapper<string> _Name;
    public Wrapper<string> Name {
        get { return _Name; }
        set { _Name = (string)value; }
    }
}
CustomerTable customer = new CustomerTable();
UserTable user = new UserTable();

user.Name = customer.Name; //*** No longer breaks internal data structures

user.Name = "string literal";  // Works as expected with implicit cast operator
user.Name = (string)customer.Name; // Still allowed with explicit/implicit cast operator
user.Name = customer.Name.Value; // Also works if Value property is still defined