Programing

ReSharper는 경고 : "일반 유형의 정적 필드"

lottogame 2020. 4. 6. 07:58
반응형

ReSharper는 경고 : "일반 유형의 정적 필드"


public class EnumRouteConstraint<T> : IRouteConstraint
    where T : struct
{
    private static readonly Lazy<HashSet<string>> _enumNames; // <--

    static EnumRouteConstraint()
    {
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException(
                Resources.Error.EnumRouteConstraint.FormatWith(typeof(T).FullName));
        }

        string[] names = Enum.GetNames(typeof(T));
        _enumNames = new Lazy<HashSet<string>>(() => new HashSet<string>
        (
            names.Select(name => name), StringComparer.InvariantCultureIgnoreCase
        ));
    }

    public bool Match(HttpContextBase httpContext, Route route, 
                        string parameterName, RouteValueDictionary values, 
                        RouteDirection routeDirection)
    {
        bool match = _enumNames.Value.Contains(values[parameterName].ToString());
        return match;
    }
}

이것이 잘못 되었습니까? 나는 이것이 실제로 내가 일어날 static readonlyEnumRouteConstraint<T>있는 각각의 필드를 가지고 있다고 가정 합니다.


유형 인수 조합마다 실제로 하나의 필드를 얻는다는 것을 알고 있다면 제네릭 유형의 정적 필드를 사용하는 것이 좋습니다. 내 생각에 R #은 알지 못하는 경우를 대비하여 경고합니다.

그 예는 다음과 같습니다.

using System;

public class Generic<T>
{
    // Of course we wouldn't normally have public fields, but...
    public static int Foo;
}

public class Test
{
    public static void Main()
    {
        Generic<string>.Foo = 20;
        Generic<object>.Foo = 10;
        Console.WriteLine(Generic<string>.Foo); // 20
    }
}

보시다시피 Generic<string>.Foo, 다른 필드는 Generic<object>.Foo별도의 값을 보유합니다.


로부터 JetBrains의 위키 :

대부분의 경우 제네릭 형식의 정적 필드를 갖는 것은 오류의 신호입니다. 그 이유는 제네릭 형식의 정적 필드 가 다른 밀접하게 구성된 형식의 인스턴스간에 공유 되지 않기 때문입니다. 일반적인 클래스한다는 수단이 C<T>정적 필드가 X상기의 값 C<int>.X과는 C<string>.X전혀 다른, 독립된 값을 갖는다.

드문 경우이지만 '특수화 된'정적 필드 필요한 경우 경고를 자유롭게 억제하십시오.

제네릭 인수가 다른 인스턴스간에 정적 필드를 공유해야하는 경우 제네릭이 아닌 기본 클래스를 정의 하여 정적 멤버를 저장 한 다음 제네릭 형식을이 형식에서 상속하도록 설정하십시오.


이것은 반드시 오류는 아닙니다 . C # 제네릭 에 대한 잠재적 오해대해 경고합니다 .

제네릭의 기능을 기억하는 가장 쉬운 방법은 다음과 같습니다. 제네릭은 클래스를 만들기위한 "청사진"입니다. 클래스는 객체를 만들기위한 "청사진"입니다. (그러나 이것은 단순화입니다. 메소드 제네릭도 사용할 수 있습니다.)

이 관점 MyClassRecipe<T>에서 수업은 수업이 아니라 수업 의 모습을 보여주는 레시피, 청사진입니다. int, string 등과 같은 구체적인 무언가로 T를 대체하면 클래스가 생깁니다. 새로 생성 된 클래스 (다른 클래스와 마찬가지로)에 정적 멤버 (필드, 속성, 메소드)를 선언하고 여기에 오류가없는 것은 완벽하게 합법적입니다. static MyStaticProperty<T> Property { get; set; }클래스 청사진 내에서 선언하면 언뜻보기에는 다소 의심 스럽지만 합법적입니다. 귀하의 재산은 매개 변수화되거나 템플릿 화됩니다.

VB 스태틱에서 호출되는 것은 놀라운 일이 아닙니다 shared. 그러나이 경우 이러한 "공유"멤버는 동일한 클래스의 인스턴스간에 만 공유되며 다른 클래스로 대체 <T>하여 생성 된 고유 클래스 간에는 공유되지 않습니다 .


여기에 경고와 그 이유를 설명하는 몇 가지 좋은 답변이 이미 있습니다. 이러한 유형 중 일부는 제네릭 형식의 정적 필드를 갖는 것이 일반적으로 실수 입니다.

이 기능이 어떻게 유용 할 수 있는지, 예를 들어 R # 경고를 억제하는 것이 좋은지에 대한 예를 추가한다고 생각했습니다.

Xml과 같이 직렬화하려는 엔터티 클래스 집합이 있다고 가정하십시오. 을 사용하여이를위한 직렬 변환기를 작성할 수 new XmlSerializerFactory().CreateSerializer(typeof(SomeClass))있지만 각 유형마다 별도의 직렬 변환기를 작성해야합니다. 제네릭을 사용하면 다음과 같이 대체 할 수 있으며 엔터티에서 파생되는 제네릭 클래스에 배치 할 수 있습니다.

new XmlSerializerFactory().CreateSerializer(typeof(T))

특정 유형의 인스턴스를 직렬화해야 할 때마다 새 직렬 변환기를 생성하지 않으려는 경우 다음을 추가 할 수 있습니다.

public class SerializableEntity<T>
{
    // ReSharper disable once StaticMemberInGenericType
    private static XmlSerializer _typeSpecificSerializer;

    private static XmlSerializer TypeSpecificSerializer
    {
        get
        {
            // Only create an instance the first time. In practice, 
            // that will mean once for each variation of T that is used,
            // as each will cause a new class to be created.
            if ((_typeSpecificSerializer == null))
            {
                _typeSpecificSerializer = 
                    new XmlSerializerFactory().CreateSerializer(typeof(T));
            }

            return _typeSpecificSerializer;
        }
    }

    public virtual string Serialize()
    {
        // .... prepare for serializing...

        // Access _typeSpecificSerializer via the property, 
        // and call the Serialize method, which depends on 
        // the specific type T of "this":
        TypeSpecificSerializer.Serialize(xmlWriter, this);
     }
}

이 클래스가 제네릭이 아닌 경우 클래스의 각 인스턴스는 동일한를 사용합니다 _typeSpecificSerializer.

그러나 일반 유형이므로에 대해 동일한 유형의 인스턴스 세트 T는 단일 인스턴스 _typeSpecificSerializer(특정 유형에 대해 작성 됨)를 공유하는 반면, 유형 T이 다른 인스턴스는의 다른 인스턴스를 사용합니다 _typeSpecificSerializer.

다음 두 가지 클래스를 제공합니다 SerializableEntity<T>.

// Note that T is MyFirstEntity
public class MyFirstEntity : SerializableEntity<MyFirstEntity>
{
    public string SomeValue { get; set; }
}

// Note that T is OtherEntity
public class OtherEntity : SerializableEntity<OtherEntity >
{
    public int OtherValue { get; set; }
}

... 사용해 봅시다 :

var firstInst = new MyFirstEntity{ SomeValue = "Foo" };
var secondInst = new MyFirstEntity{ SomeValue = "Bar" };

var thirdInst = new OtherEntity { OtherValue = 123 };
var fourthInst = new OtherEntity { OtherValue = 456 };

var xmlData1 = firstInst.Serialize();
var xmlData2 = secondInst.Serialize();
var xmlData3 = thirdInst.Serialize();
var xmlData4 = fourthInst.Serialize();

이 경우, 후드, firstInstsecondInst동일 클래스 (즉, 인스턴스의 것 SerializableEntity<MyFirstEntity>)과 같은 그들 인스턴스를 공유 할 것이다 _typeSpecificSerializer.

thirdInst그리고 fourthInst다른 클래스 (의 인스턴스이다 SerializableEntity<OtherEntity>), 그리고 이렇게 인스턴스를 공유 _typeSpecificSerializer다른 다른 두에서.

즉, 각 엔터티 유형 마다 서로 다른 serializer 인스턴스를 얻는 동시에 각 실제 유형의 컨텍스트 내에서 정적 상태를 유지합니다 (예 : 특정 유형의 인스턴스간에 공유).

참고 URL : https://stackoverflow.com/questions/9647641/resharper-warns-static-field-in-generic-type

반응형