How can I avoid code duplication of a static method in multiple classes
I have multiple classes containing duplicated code, especially members and most important a static method that will create a new instance of the class and returning this instance: either a previously created instance registered in a dictionary or a new instance by calling the constructor.
An interface is no option, because I have the static method. I tried to solve the problem by introducing a base class that implements this static method, but I can not find a way to create and return a spefific child class properly.
Below is a code example of the current situation with class A and class B showing duplicated code.
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;
}
}
}
And then in class B again there is a member Name and the GetX() Method.
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;
}
}
}
Is there a possibility to avoid this kind of code duplication by introducing a base class or any other way?
c# inheritance code-duplication static-polymorphism
|
show 1 more comment
I have multiple classes containing duplicated code, especially members and most important a static method that will create a new instance of the class and returning this instance: either a previously created instance registered in a dictionary or a new instance by calling the constructor.
An interface is no option, because I have the static method. I tried to solve the problem by introducing a base class that implements this static method, but I can not find a way to create and return a spefific child class properly.
Below is a code example of the current situation with class A and class B showing duplicated code.
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;
}
}
}
And then in class B again there is a member Name and the GetX() Method.
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;
}
}
}
Is there a possibility to avoid this kind of code duplication by introducing a base class or any other way?
c# inheritance code-duplication static-polymorphism
2
Mabe make the base method, accepting a generic type and then create instance from that. see stackoverflow.com/questions/731452/…
– Malior
Jan 3 at 10:28
But if dictionary will be static, then you will share the same dictionary over betweenA
andB
, which may be not what you want.
– Michał Turczyn
Jan 3 at 10:32
Is the constructorpublic
visibility intended ?
– Spotted
Jan 3 at 10:45
Why do you want to limit the number of instance based oninstanceName
? Is it allowed that both an instance ofA
and an instance ofB
with the sameinstanceName
?
– Spotted
Jan 3 at 11:06
Name
can be a part of base class/interface. As forGetX
you can't avoid declaration of it, unless you can make it generic, then base class is where it should normally be. You can still declare type specific static method to invoke that generic method for the comfort of those type users.
– Sinatr
Jan 3 at 11:11
|
show 1 more comment
I have multiple classes containing duplicated code, especially members and most important a static method that will create a new instance of the class and returning this instance: either a previously created instance registered in a dictionary or a new instance by calling the constructor.
An interface is no option, because I have the static method. I tried to solve the problem by introducing a base class that implements this static method, but I can not find a way to create and return a spefific child class properly.
Below is a code example of the current situation with class A and class B showing duplicated code.
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;
}
}
}
And then in class B again there is a member Name and the GetX() Method.
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;
}
}
}
Is there a possibility to avoid this kind of code duplication by introducing a base class or any other way?
c# inheritance code-duplication static-polymorphism
I have multiple classes containing duplicated code, especially members and most important a static method that will create a new instance of the class and returning this instance: either a previously created instance registered in a dictionary or a new instance by calling the constructor.
An interface is no option, because I have the static method. I tried to solve the problem by introducing a base class that implements this static method, but I can not find a way to create and return a spefific child class properly.
Below is a code example of the current situation with class A and class B showing duplicated code.
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;
}
}
}
And then in class B again there is a member Name and the GetX() Method.
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;
}
}
}
Is there a possibility to avoid this kind of code duplication by introducing a base class or any other way?
c# inheritance code-duplication static-polymorphism
c# inheritance code-duplication static-polymorphism
edited Jan 3 at 11:21
Wai Ha Lee
6,096124065
6,096124065
asked Jan 3 at 10:16
user7330525user7330525
309
309
2
Mabe make the base method, accepting a generic type and then create instance from that. see stackoverflow.com/questions/731452/…
– Malior
Jan 3 at 10:28
But if dictionary will be static, then you will share the same dictionary over betweenA
andB
, which may be not what you want.
– Michał Turczyn
Jan 3 at 10:32
Is the constructorpublic
visibility intended ?
– Spotted
Jan 3 at 10:45
Why do you want to limit the number of instance based oninstanceName
? Is it allowed that both an instance ofA
and an instance ofB
with the sameinstanceName
?
– Spotted
Jan 3 at 11:06
Name
can be a part of base class/interface. As forGetX
you can't avoid declaration of it, unless you can make it generic, then base class is where it should normally be. You can still declare type specific static method to invoke that generic method for the comfort of those type users.
– Sinatr
Jan 3 at 11:11
|
show 1 more comment
2
Mabe make the base method, accepting a generic type and then create instance from that. see stackoverflow.com/questions/731452/…
– Malior
Jan 3 at 10:28
But if dictionary will be static, then you will share the same dictionary over betweenA
andB
, which may be not what you want.
– Michał Turczyn
Jan 3 at 10:32
Is the constructorpublic
visibility intended ?
– Spotted
Jan 3 at 10:45
Why do you want to limit the number of instance based oninstanceName
? Is it allowed that both an instance ofA
and an instance ofB
with the sameinstanceName
?
– Spotted
Jan 3 at 11:06
Name
can be a part of base class/interface. As forGetX
you can't avoid declaration of it, unless you can make it generic, then base class is where it should normally be. You can still declare type specific static method to invoke that generic method for the comfort of those type users.
– Sinatr
Jan 3 at 11:11
2
2
Mabe make the base method, accepting a generic type and then create instance from that. see stackoverflow.com/questions/731452/…
– Malior
Jan 3 at 10:28
Mabe make the base method, accepting a generic type and then create instance from that. see stackoverflow.com/questions/731452/…
– Malior
Jan 3 at 10:28
But if dictionary will be static, then you will share the same dictionary over between
A
and B
, which may be not what you want.– Michał Turczyn
Jan 3 at 10:32
But if dictionary will be static, then you will share the same dictionary over between
A
and B
, which may be not what you want.– Michał Turczyn
Jan 3 at 10:32
Is the constructor
public
visibility intended ?– Spotted
Jan 3 at 10:45
Is the constructor
public
visibility intended ?– Spotted
Jan 3 at 10:45
Why do you want to limit the number of instance based on
instanceName
? Is it allowed that both an instance of A
and an instance of B
with the same instanceName
?– Spotted
Jan 3 at 11:06
Why do you want to limit the number of instance based on
instanceName
? Is it allowed that both an instance of A
and an instance of B
with the same instanceName
?– Spotted
Jan 3 at 11:06
Name
can be a part of base class/interface. As for GetX
you can't avoid declaration of it, unless you can make it generic, then base class is where it should normally be. You can still declare type specific static method to invoke that generic method for the comfort of those type users.– Sinatr
Jan 3 at 11:11
Name
can be a part of base class/interface. As for GetX
you can't avoid declaration of it, unless you can make it generic, then base class is where it should normally be. You can still declare type specific static method to invoke that generic method for the comfort of those type users.– Sinatr
Jan 3 at 11:11
|
show 1 more comment
4 Answers
4
active
oldest
votes
This might be a little cleaner:
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;
}
}
}
You forgot to add to theRegistry
when you were creating a new instance. That way, it will never hit the dictionary.
– Anderson Pimentel
Jan 3 at 10:40
1
@AndersonPimentel, noticed as soon as I posted it. Thanks for noticing. Great answer btw.
– John Babb
Jan 3 at 10:47
Thanks @JohnBabb for that helpful approach.
– user7330525
Jan 3 at 12:03
add a comment |
Are you looking for a generic base 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;
}
}
}
And then use it like this:
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));
}
}
The source for the awkward approach to make sure there is a string-constructor for A can be found here.
add a comment |
I think this should work. You can adapt it to fit your needs. Also, there was a bug in your code: you forgot to add to the Registry
when you were creating a new instance.
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;
}
}
}
add a comment |
All the other answers try to solve this with generics, but it might be the case you wouldn't want to do this. First, it could be an unnecessary restriction further along that could end up causing variance issues. Second, it only solves one level of inheritance, if there is more, you are stuck again with the same problem:
class Base<T> { ... }
class A: Base<A> { ... }
class B: A { //How does the generic base class help? }
There are general solutions without the use generics that entails just a little code duplication. One could be the following:
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;
}
}
//...
}
And now yor derived types can impement a strongly typed delegated method:
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;
}
Did you forget to add toRegistry
in your first code sample? CouldRegistry
instead be aConcurrentDictionary
(perhaps where the value isLazy
)?
– mjwills
Jan 3 at 11:08
@sinatr Sorry about the mess, I really need to go to bed. This is more or less what I had in mind. And yes, another option is makingRegister
generic and callingActivator.CreateInstance
but that relies on reflection...
– InBetween
Jan 3 at 11:45
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54020243%2fhow-can-i-avoid-code-duplication-of-a-static-method-in-multiple-classes%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
This might be a little cleaner:
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;
}
}
}
You forgot to add to theRegistry
when you were creating a new instance. That way, it will never hit the dictionary.
– Anderson Pimentel
Jan 3 at 10:40
1
@AndersonPimentel, noticed as soon as I posted it. Thanks for noticing. Great answer btw.
– John Babb
Jan 3 at 10:47
Thanks @JohnBabb for that helpful approach.
– user7330525
Jan 3 at 12:03
add a comment |
This might be a little cleaner:
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;
}
}
}
You forgot to add to theRegistry
when you were creating a new instance. That way, it will never hit the dictionary.
– Anderson Pimentel
Jan 3 at 10:40
1
@AndersonPimentel, noticed as soon as I posted it. Thanks for noticing. Great answer btw.
– John Babb
Jan 3 at 10:47
Thanks @JohnBabb for that helpful approach.
– user7330525
Jan 3 at 12:03
add a comment |
This might be a little cleaner:
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;
}
}
}
This might be a little cleaner:
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;
}
}
}
edited Jan 3 at 10:41
answered Jan 3 at 10:38
John BabbJohn Babb
8771018
8771018
You forgot to add to theRegistry
when you were creating a new instance. That way, it will never hit the dictionary.
– Anderson Pimentel
Jan 3 at 10:40
1
@AndersonPimentel, noticed as soon as I posted it. Thanks for noticing. Great answer btw.
– John Babb
Jan 3 at 10:47
Thanks @JohnBabb for that helpful approach.
– user7330525
Jan 3 at 12:03
add a comment |
You forgot to add to theRegistry
when you were creating a new instance. That way, it will never hit the dictionary.
– Anderson Pimentel
Jan 3 at 10:40
1
@AndersonPimentel, noticed as soon as I posted it. Thanks for noticing. Great answer btw.
– John Babb
Jan 3 at 10:47
Thanks @JohnBabb for that helpful approach.
– user7330525
Jan 3 at 12:03
You forgot to add to the
Registry
when you were creating a new instance. That way, it will never hit the dictionary.– Anderson Pimentel
Jan 3 at 10:40
You forgot to add to the
Registry
when you were creating a new instance. That way, it will never hit the dictionary.– Anderson Pimentel
Jan 3 at 10:40
1
1
@AndersonPimentel, noticed as soon as I posted it. Thanks for noticing. Great answer btw.
– John Babb
Jan 3 at 10:47
@AndersonPimentel, noticed as soon as I posted it. Thanks for noticing. Great answer btw.
– John Babb
Jan 3 at 10:47
Thanks @JohnBabb for that helpful approach.
– user7330525
Jan 3 at 12:03
Thanks @JohnBabb for that helpful approach.
– user7330525
Jan 3 at 12:03
add a comment |
Are you looking for a generic base 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;
}
}
}
And then use it like this:
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));
}
}
The source for the awkward approach to make sure there is a string-constructor for A can be found here.
add a comment |
Are you looking for a generic base 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;
}
}
}
And then use it like this:
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));
}
}
The source for the awkward approach to make sure there is a string-constructor for A can be found here.
add a comment |
Are you looking for a generic base 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;
}
}
}
And then use it like this:
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));
}
}
The source for the awkward approach to make sure there is a string-constructor for A can be found here.
Are you looking for a generic base 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;
}
}
}
And then use it like this:
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));
}
}
The source for the awkward approach to make sure there is a string-constructor for A can be found here.
answered Jan 3 at 10:31
CompufreakCompufreak
2,12711130
2,12711130
add a comment |
add a comment |
I think this should work. You can adapt it to fit your needs. Also, there was a bug in your code: you forgot to add to the Registry
when you were creating a new instance.
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;
}
}
}
add a comment |
I think this should work. You can adapt it to fit your needs. Also, there was a bug in your code: you forgot to add to the Registry
when you were creating a new instance.
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;
}
}
}
add a comment |
I think this should work. You can adapt it to fit your needs. Also, there was a bug in your code: you forgot to add to the Registry
when you were creating a new instance.
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;
}
}
}
I think this should work. You can adapt it to fit your needs. Also, there was a bug in your code: you forgot to add to the Registry
when you were creating a new instance.
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;
}
}
}
answered Jan 3 at 10:37
Anderson PimentelAnderson Pimentel
3,73122245
3,73122245
add a comment |
add a comment |
All the other answers try to solve this with generics, but it might be the case you wouldn't want to do this. First, it could be an unnecessary restriction further along that could end up causing variance issues. Second, it only solves one level of inheritance, if there is more, you are stuck again with the same problem:
class Base<T> { ... }
class A: Base<A> { ... }
class B: A { //How does the generic base class help? }
There are general solutions without the use generics that entails just a little code duplication. One could be the following:
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;
}
}
//...
}
And now yor derived types can impement a strongly typed delegated method:
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;
}
Did you forget to add toRegistry
in your first code sample? CouldRegistry
instead be aConcurrentDictionary
(perhaps where the value isLazy
)?
– mjwills
Jan 3 at 11:08
@sinatr Sorry about the mess, I really need to go to bed. This is more or less what I had in mind. And yes, another option is makingRegister
generic and callingActivator.CreateInstance
but that relies on reflection...
– InBetween
Jan 3 at 11:45
add a comment |
All the other answers try to solve this with generics, but it might be the case you wouldn't want to do this. First, it could be an unnecessary restriction further along that could end up causing variance issues. Second, it only solves one level of inheritance, if there is more, you are stuck again with the same problem:
class Base<T> { ... }
class A: Base<A> { ... }
class B: A { //How does the generic base class help? }
There are general solutions without the use generics that entails just a little code duplication. One could be the following:
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;
}
}
//...
}
And now yor derived types can impement a strongly typed delegated method:
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;
}
Did you forget to add toRegistry
in your first code sample? CouldRegistry
instead be aConcurrentDictionary
(perhaps where the value isLazy
)?
– mjwills
Jan 3 at 11:08
@sinatr Sorry about the mess, I really need to go to bed. This is more or less what I had in mind. And yes, another option is makingRegister
generic and callingActivator.CreateInstance
but that relies on reflection...
– InBetween
Jan 3 at 11:45
add a comment |
All the other answers try to solve this with generics, but it might be the case you wouldn't want to do this. First, it could be an unnecessary restriction further along that could end up causing variance issues. Second, it only solves one level of inheritance, if there is more, you are stuck again with the same problem:
class Base<T> { ... }
class A: Base<A> { ... }
class B: A { //How does the generic base class help? }
There are general solutions without the use generics that entails just a little code duplication. One could be the following:
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;
}
}
//...
}
And now yor derived types can impement a strongly typed delegated method:
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;
}
All the other answers try to solve this with generics, but it might be the case you wouldn't want to do this. First, it could be an unnecessary restriction further along that could end up causing variance issues. Second, it only solves one level of inheritance, if there is more, you are stuck again with the same problem:
class Base<T> { ... }
class A: Base<A> { ... }
class B: A { //How does the generic base class help? }
There are general solutions without the use generics that entails just a little code duplication. One could be the following:
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;
}
}
//...
}
And now yor derived types can impement a strongly typed delegated method:
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;
}
edited Jan 3 at 11:40
answered Jan 3 at 11:00
InBetweenInBetween
25.4k34068
25.4k34068
Did you forget to add toRegistry
in your first code sample? CouldRegistry
instead be aConcurrentDictionary
(perhaps where the value isLazy
)?
– mjwills
Jan 3 at 11:08
@sinatr Sorry about the mess, I really need to go to bed. This is more or less what I had in mind. And yes, another option is makingRegister
generic and callingActivator.CreateInstance
but that relies on reflection...
– InBetween
Jan 3 at 11:45
add a comment |
Did you forget to add toRegistry
in your first code sample? CouldRegistry
instead be aConcurrentDictionary
(perhaps where the value isLazy
)?
– mjwills
Jan 3 at 11:08
@sinatr Sorry about the mess, I really need to go to bed. This is more or less what I had in mind. And yes, another option is makingRegister
generic and callingActivator.CreateInstance
but that relies on reflection...
– InBetween
Jan 3 at 11:45
Did you forget to add to
Registry
in your first code sample? Could Registry
instead be a ConcurrentDictionary
(perhaps where the value is Lazy
)?– mjwills
Jan 3 at 11:08
Did you forget to add to
Registry
in your first code sample? Could Registry
instead be a ConcurrentDictionary
(perhaps where the value is Lazy
)?– mjwills
Jan 3 at 11:08
@sinatr Sorry about the mess, I really need to go to bed. This is more or less what I had in mind. And yes, another option is making
Register
generic and calling Activator.CreateInstance
but that relies on reflection...– InBetween
Jan 3 at 11:45
@sinatr Sorry about the mess, I really need to go to bed. This is more or less what I had in mind. And yes, another option is making
Register
generic and calling Activator.CreateInstance
but that relies on reflection...– InBetween
Jan 3 at 11:45
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54020243%2fhow-can-i-avoid-code-duplication-of-a-static-method-in-multiple-classes%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
Mabe make the base method, accepting a generic type and then create instance from that. see stackoverflow.com/questions/731452/…
– Malior
Jan 3 at 10:28
But if dictionary will be static, then you will share the same dictionary over between
A
andB
, which may be not what you want.– Michał Turczyn
Jan 3 at 10:32
Is the constructor
public
visibility intended ?– Spotted
Jan 3 at 10:45
Why do you want to limit the number of instance based on
instanceName
? Is it allowed that both an instance ofA
and an instance ofB
with the sameinstanceName
?– Spotted
Jan 3 at 11:06
Name
can be a part of base class/interface. As forGetX
you can't avoid declaration of it, unless you can make it generic, then base class is where it should normally be. You can still declare type specific static method to invoke that generic method for the comfort of those type users.– Sinatr
Jan 3 at 11:11