切换出'this'构造函数中静态类成员的指针

本文关键字:成员 指针 静态类 this 换出 构造函数 | 更新日期: 2023-09-27 18:06:24

假设我有一个类,它本身有静态成员,就像单例一样。我也允许构造这个类。如果消费者构造具有已知的参数,我希望返回一个静态成员,而不是一个新的构造。

下面是说明这一点的非编译示例代码。从本质上讲,我希望像Construct方法中所示的那样构造类,但我不希望类的消费者被迫重写他现有的new MyClass(0)调用。

这可能吗?

public class MyClass
{
    public static readonly MyClass Zero = new MyClass(0);
    private int n;
    public static MyClass Construct(int n)
    {
        MyClass self = new MyClass(0, true); //the bool just helps with referencing
        ReplaceIfZero(ref self);
        return self;
    }
    public MyClass(int n, bool x) //the bool is just so i can reference it in this example
    {
        this.n = n;
    }
    public MyClass(int n)
    {
        this.n = n;
        ReplaceIfZero(ref this); 
        // Error CS1605  Cannot pass 'this' as a ref or out argument because it is read - only
    }
    ReplaceIfZero(ref MyClass myclass)
    {
        if(Zero.Equals(myclass))
        {
            myclass = Zero;
        }
    }
    public override bool Equals(object obj)
    {
        return ReferenceEquals(this, obj) || ( (obj is MyClass) && n.Equals((obj as MyClass).n) );
    }
}

切换出'this'构造函数中静态类成员的指针

通常的解决方案是将构造函数设置为私有,并添加一个公共静态工厂方法来处理这些事情。我认为这是最好的办法。

然而,另一种方法是使用接口和包装器类隐藏细节。

像这样:

public interface IMyClass
{
    int SomeMethod(int x);
}
public class MyClass: IMyClass
{
    public MyClass(int n)
    {
        _impl = MyClassImpl.Create(n);
    }
    public int SomeMethod(int x)
    {
        return _impl.SomeMethod(x);
    }
    // For test purposes only - see later in this answer.
    public bool ImplementationEquals(MyClass other)
    {
        return ReferenceEquals(_impl, other._impl);
    }
    readonly IMyClass _impl;
}
internal class MyClassImpl : IMyClass
{
    static readonly ConcurrentDictionary<int, IMyClass> _dict = new ConcurrentDictionary<int, IMyClass>();
    readonly int _n;
    MyClassImpl(int n)
    {
        _n = n;
    }
    public static IMyClass Create(int n)
    {
        return _dict.GetOrAdd(n, i => new MyClassImpl(i));
    }
    public int SomeMethod(int x)
    {
        return _n + x;
    }
}

客户端代码可以创建MyClass的实例,并且在幕后使用另一个类来实现。

如果客户端代码创建了两个MyClass实例,则实现对象将被共享,如下面的代码所示:

var a = new MyClass(1);
var b = new MyClass(2);
var c = new MyClass(1);
Console.WriteLine(a.ImplementationEquals(b)); // Prints false
Console.WriteLine(a.ImplementationEquals(c)); // Prints true

还请注意,如果您这样做,该类是强不可变的是非常重要的(即它的所有字段都是不可变的,如果一个字段不是基本类型,它的所有字段都是递归不可变的)

正如我在评论中提到的,c#不允许您更改new操作符的结果。它总是返回一个新的类实例。当然,我们说的是普通类,而不是像ContextBoundObject和代理这样的特殊黑客。

所以没有办法让您的客户端使用new操作符并获得所需的行为。您需要删除公共构造函数,并强制您的客户端使用一些公共静态工厂方法,如MyClass.Create(或Construct,如您的示例)。

据我所知,从你的代码,你想提供相同的对象,如果用户为另一个实例创建相同的数字。如果是这样,最好使用工厂模式或单例模式

你似乎只需要一个类的实例。

会更容易创建一个静态类,不是吗?

public static class MyClass
{
    static MyClass()
    {
        n_ = 2;
    }
    private static int n_;
    public static void Construct(int number)
    {
        n_= number;
    }
}