我有多个包含重复代码的类,尤其是成员,最重要的是一个静态方法,该方法将创建该类的新实例并返回该实例:是在字典中注册的先前创建的实例,还是通过调用构造函数注册的新实例
接口是没有选择的,因为我有静态方法。我试图通过引入实现此静态方法的基类来解决该问题,但我找不到正确创建和返回特定子类的方法。
下面是当前情况的代码示例,其中A类和B类显示重复的代码。
public class A
{
private static readonly IDictionary<string, A> Registry = new Dictionary<string, A>();
public string Name { get; set; }
public A(string name)
{
this.Name = name;
}
public static A GetA(string instanceName)
{
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = new A(instanceName);
}
return newInstance;
}
}
}
然后在B类中再次有一个成员Name和GetX()方法。
public class B
{
private static readonly IDictionary<string, B> Registry = new Dictionary<string, B>();
public string Name { get; set; }
public B(string name)
{
this.Name = name;
}
public static B GetB(string instanceName)
{
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = new B(instanceName);
}
return newInstance;
}
}
}
是否有可能通过引入基类或任何其他方式来避免这种代码重复?
答案 0 :(得分:2)
这可能会更清洁一些
public class B: RegistryInstance<B>
{
public string Name { get; set; }
public B(string name)
{
this.Name = name;
}
}
public class A : RegistryInstance<A>
{
public string Name { get; set; }
public A(string name)
{
this.Name = name;
}
}
public abstract class RegistryInstance<T> where T:class
{
protected static readonly IDictionary<string, T> Registry = new Dictionary<string, T>();
public static T GetInstance(string instanceName)
{
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = (T)Activator.CreateInstance(typeof(T), new object[] { instanceName });
Registry.Add(instanceName, newInstance);
}
return newInstance;
}
}
}
答案 1 :(得分:1)
您要寻找通用的基类吗?
public abstract class BaseRegistryGetter<T>
{
private static readonly IDictionary<string, T> Registry = new Dictionary<string, T>();
public string Name { get; set; }
public BaseRegistryGetter(string name)
{
this.Name = name;
}
public static T GetValue (string instanceName, Func<string, T> creator) {
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = creator(instanceName);
}
return newInstance;
}
}
}
然后像这样使用它:
public class A : BaseRegistryGetter<A>
{
public A(string name) : base(name)
{
}
public static A GetA(string instanceName)
{
return BaseRegistryGetter<A>.GetValue(instanceName, s => new A(s));
}
}
在here中可以找到笨拙的方法来确保A的字符串构造器。
答案 2 :(得分:0)
我认为这应该有效。您可以对其进行调整以满足您的需求。另外,您的代码中存在一个错误:创建新实例时,您忘记添加到Registry
中。
class Program
{
static void Main(string[] args)
{
A a1 = A.GetInstance("a");
A a2 = A.GetInstance("aa");
A a3 = A.GetInstance("a");
B b1 = B.GetInstance("a");
B b2 = B.GetInstance("aa");
B b3 = B.GetInstance("a");
Console.WriteLine(a1 == a2); //false
Console.WriteLine(a1 == a3); //true
Console.WriteLine(b1 == b2); //false
Console.WriteLine(b1 == b3); //true
Console.ReadKey();
}
}
public class A : Generic<A>
{
public A(string name)
: base(name)
{
}
}
public class B : Generic<B>
{
public B(string name)
: base(name)
{
}
}
public abstract class Generic<T> where T : Generic<T>
{
private static readonly IDictionary<string, T> Registry = new Dictionary<string, T>();
public string Name { get; set; }
public Generic(string name)
{
this.Name = name;
}
public static T GetInstance(string instanceName)
{
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = (T)Activator.CreateInstance(typeof(T), instanceName);
Registry.Add(instanceName, newInstance);
}
return newInstance;
}
}
}
答案 3 :(得分:0)
所有其他答案都尝试使用泛型来解决此问题,但您可能不想这样做。首先,这可能是不必要的限制,最终可能导致差异问题。其次,它只能解决一个继承级别,如果继承更多,则会再次遇到相同的问题:
class Base<T> { ... }
class A: Base<A> { ... }
class B: A { //How does the generic base class help? }
有些通用解决方案没有使用泛型,因此只需要一点代码重复。一种可能是以下情况:
public class Base
{
static readonly IDictionary<string, Base> Registry =
new Dictionary<string, Base>();
protected static Base GetBase(string instanceName,
Func<Base> creator)
{
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = creator();
}
return newInstance;
}
}
//...
}
现在,您的派生类型可以实现强类型的委托方法:
public class A: Base
{
public A(string instanceName)
:base(instanceName)
{
}
public static A GetA(string instanceName)
=> GetBase(instanceName, () => new A(instanceName)) as A;
}
public class B: Base
{
public B(string instanceName)
:base(instanceName)
{
}
public static B GetB(string instanceName)
=> GetBase(instanceName, () => new B(instanceName)) as B;
}