如何避免多个 类 中静态方法的代码重复
How can I avoid code duplication of a static method in multiple classes
我有多个包含重复代码的 classes,尤其是成员和最重要的静态方法,它将创建 class 的新实例并 returning 这个实例:要么先前创建的实例在字典中注册或通过调用构造函数创建新实例。
接口不是选项,因为我有静态方法。我试图通过引入实现此静态方法的基础 class 来解决问题,但我找不到正确创建和 return 特定子 class 的方法。
下面是当前情况的代码示例,其中 class A 和 class 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;
}
}
}
然后在 class B 中再次有一个成员名称和 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;
}
}
}
是否可以通过引入基数 class 或任何其他方式来避免这种代码重复?
您是否在寻找通用基础 class?
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));
}
}
可以找到确保 A 有字符串构造函数的尴尬方法的来源 here。
我认为这应该可行。您可以调整它以满足您的需要。另外,您的代码中有一个错误:您在创建新实例时忘记添加到 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;
}
}
}
这可能更干净一些:
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;
}
}
}
所有其他答案都试图用泛型来解决这个问题,但您可能不想这样做。首先,这可能是一个不必要的限制,最终可能会导致差异问题。第二,它只解决了一级继承,如果有更多,你又被同样的问题卡住了:
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;
}
我有多个包含重复代码的 classes,尤其是成员和最重要的静态方法,它将创建 class 的新实例并 returning 这个实例:要么先前创建的实例在字典中注册或通过调用构造函数创建新实例。
接口不是选项,因为我有静态方法。我试图通过引入实现此静态方法的基础 class 来解决问题,但我找不到正确创建和 return 特定子 class 的方法。
下面是当前情况的代码示例,其中 class A 和 class 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;
}
}
}
然后在 class B 中再次有一个成员名称和 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;
}
}
}
是否可以通过引入基数 class 或任何其他方式来避免这种代码重复?
您是否在寻找通用基础 class?
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));
}
}
可以找到确保 A 有字符串构造函数的尴尬方法的来源 here。
我认为这应该可行。您可以调整它以满足您的需要。另外,您的代码中有一个错误:您在创建新实例时忘记添加到 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;
}
}
}
这可能更干净一些:
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;
}
}
}
所有其他答案都试图用泛型来解决这个问题,但您可能不想这样做。首先,这可能是一个不必要的限制,最终可能会导致差异问题。第二,它只解决了一级继承,如果有更多,你又被同样的问题卡住了:
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;
}