切换出'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) );
}
}
通常的解决方案是将构造函数设置为私有,并添加一个公共静态工厂方法来处理这些事情。我认为这是最好的办法。
然而,另一种方法是使用接口和包装器类隐藏细节。
像这样:
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;
}
}