3

I am trying to figure out a way I can make use of private static fields in a generic class. This is the obvious way to do it (fiddle). It won't compile because Field is not accessible in BaseChild, and ideally I wouldn't want it to be accessible there:

public class Base<T>
{
    private static readonly string Field = "field";

    public Base()
    {
        Console.WriteLine(Field);
    }
}

public class BaseChild : Base<string>
{
    public BaseChild()
    {
        Console.WriteLine(Field);
    }
}

The problem with this solution is that there is a different Field for each generic type, instead of being shared across them.

I have seen this answer where it says that JetBrains recommends a solution for static fields across generic types:

If you need to have a static field shared between instances with different generic arguments, define a non-generic base class to store your static members, then set your generic type to inherit from this type.

This makes sense for the case where you have public or protected static fields in the base class that you want to share across any child class like this example (fiddle):

public abstract class Base
{
    protected static readonly string Field = "field";
}

public class Base<T> : Base
{
    public Base()
    {
        Console.WriteLine(Field);
    }
}

public class BaseChild : Base<string>
{
    public BaseChild()
    {
        Console.WriteLine(Field);
    }
}

However, what about the case where you want to use a private static field? I would guess that this is not possible since private means only accessible to the class it's declared in and I think that since the generic class is really just a template to create a class, that any private field could only ever be shared by each class, not across all the classes created by the template.

Do I have to just put the private field in the generic class (example 1) and accept it as at least a workable solution for what I want, or is there another way I can accomplish this?

Community
  • 1
  • 1
CShark
  • 1,562
  • 1
  • 16
  • 27
  • IMHO, declaring something as `protected static` in unsealed class is essentially the same as `public static`. `protected` does not really give any protection for static members. – user4003407 Mar 23 '17 at 02:04
  • I don't necessarily agree. It keeps other non-child classes from accessing or mutating the field. Also, protected doesn't even really make any sense in a sealed class. Can you explain what you mean? – CShark Mar 23 '17 at 02:14
  • *It keeps other non-child classes from accessing or mutating the field.* Yes, but it does not stop anyone from declaring their own child classes just to access `protected static` members. – user4003407 Mar 23 '17 at 02:17
  • Yes, I agree, that's what `protected` is meant for. – CShark Mar 23 '17 at 02:22
  • @PetSerAl I'll take what you said into consideration. But, regardless, whether I set it to public or protected in my example, it doesn't change my question. I think that I have come up with an [alternate solution](http://stackoverflow.com/a/42965978/5335355) though, that doesn't use `public` or `protected`. – CShark Mar 23 '17 at 02:30
  • Are there any issues with my solution, or something I may have missed? – CShark Mar 23 '17 at 03:23

3 Answers3

2

First off -- private is doing exactly what it's made to do: to restrict access to only the type it was declared in. Keep in mind that instantiations of a generic type are all distinct types. You shouldn't be wanting to work around this.

If I understand your question correctly, you can accomplish what you want by using protected with an extra level of inheritance:

class EvenMoreBase
{
    protected static readonly string Field = "field";
}

class Base<T> : EvenMoreBase
{
    public Base()
    {
        Console.WriteLine(Field);
    }
}

class BaseChild : Base<string>
{
    public BaseChild()
    {
    Console.WriteLine(Field);
    }
}

Now each of your Base<T> will share the same instance of Field.

Cory Nelson
  • 29,236
  • 5
  • 72
  • 110
  • Yeah, I just wasn't sure if I was missing something. I'm leaning towards just having the field be private in the generic anyways, because for my actual case, I don't think the child classes should have access to the field I'm using. I would rather not just assume that no child class will touch the field. – CShark Mar 23 '17 at 01:35
1

You're correct in your thoughts on private within the base class. Whether it is static or not makes no difference.

Here's a little example:

using System;

public class Program
{
    public static void Main()
    {
        Bar b = new Bar(); // Prints "Foo"
        // Console.WriteLine(Foo.BaseField); // Compile error
    }
}

public class Foo 
{
    protected static readonly string BaseeField = "Foo";
}

public class Bar : Foo
{
    public Bar()
    {
        Console.WriteLine(Foo.BaseeField);
    }
}

Marking it protected is useful, if you'd like only your children to be able to access it. And leaving it static is how you'd keep only one instance around for all children of the base Foo class.

mariocatch
  • 8,305
  • 8
  • 50
  • 71
0

This is something I came up with that I think actually does what I want better than the initial example I put in my question. It shares a single static field across all the generic types, and it is inaccessible from children of the Base generic class.

public static class Base
{
    private static string Field = "field";

    public class Base2<T>
    {
        public Base2()
        {
            // Field is accessible here, but is the same across all generic classes
            Console.WriteLine(Field);
        }
    }
}

public class BaseChild : Base.Base2<string>
{
    public BaseChild()
    {
        //Field is not accessible here, and I don't really want it to be
        //Console.WriteLine(Field);
    }
}
CShark
  • 1,562
  • 1
  • 16
  • 27