programing

C #에서 null 인 경우에도 개체의 소문자 이름을 가져 오는 방법

nasanasas 2020. 11. 23. 08:14
반응형

C #에서 null 인 경우에도 개체의 소문자 이름을 가져 오는 방법


이 질문에 이미 답변이 있습니다.

C # 방법이 있습니다.

private static string TypeNameLower(object o)
{
   return o.GetType().Name.ToLower();
}

입력 개체의 소문자 유형 이름을 제공합니다.

그러나 입력이 null로 설정된 문자열이거나 null로 설정된 nullable int이면이 메서드는 물론 실패합니다.

이 상황에서 유형 이름을 어떻게 얻습니까?


Jeff가 맞습니다. 그것은 라벨이없는 빈 상자에 어떤 종류의 케이크가 있었는지 묻는 것과 같습니다.

Fortran의 답변에 대한 대안으로 다음을 수행 할 수도 있습니다.

string TypeNameLower<T>(T obj) {
   return typeof(T).Name.ToLower(CultureInfo.InvariantCulture);
}

string TypeNameLower(object obj) {
   if (obj != null) { return obj.GetType().Name.ToLower(CultureInfo.InvariantCulture); }
   else { return null; }
}

string s = null;
TypeNameLower(s); // goes to the generic version

이렇게하면 C #은 전달중인 형식에 대해 충분히 알고있는 경우 컴파일 타임에 제네릭을 선택합니다.


이 질문은 오래되었지만 내 답변을 게시 할 것이라고 생각했습니다. 제 생각에는 수락 된 답변이 잘못 되었기 때문입니다. 그 대답은 꽤 창의적이어서 두 드리려고하는 것은 아닙니다. 그리고 내가 아는 모든 것은 OP가 정말로 원했던 것일 수 있습니다.

그러나 아래 예제에서 볼 수 있듯이 거의 모든 경우에 허용 된 답변에 설명 된 일반 함수를 사용하는 아이디어는 (A) 불필요하거나 (B) 완전히 잘못되었다고 생각합니다. 받아 들인 대답에서 말하는 일반 함수를 복사하여 참조를 위해 아래에 붙여 넣었습니다.

string TypeNameLower<T>(T obj) {
    return typeof(T).Name.ToLower();
}

이제이 함수가 사용되는 몇 가지 방법을 살펴 보겠습니다.

일반 함수가 불필요한 예 :

var s = "hello";
var t = TypeNameLower(s);

//or
foreach(char c in "banana")
    WriteLine(TypeNameLower(c));

//or
foreach(MyCustomStruct x in listOfMyCustomStruct)
    WriteLine(TypeNameLower(x));

이 예제에서 함수는 작동합니다. 즉, 각각 "string", "char"및 "mycustomstruct"인 올바른 값을 반환합니다 . 그러나 이와 같은 모든 경우 (즉, 제네릭 함수가 실제로 올바른 유형을 반환하는 경우)에서 컴파일러는 정의 된 변수 유형이 무엇인지 미리 알고 있으며 프로그래머도 당연히 알고 있습니다 (혼란하지 않는 한 변수 이름). 따라서 함수는 완전히 불필요하며 프로그래머는 다음을 수행했을 수도 있습니다.

var s = "hello";
var t = "string";

//or
foreach(char c in "banana")
    WriteLine("char");

//or
foreach(MyCustomStruct x in listOfMyCustomStruct)
    WriteLine("mycustomstruct");

즉 걸릴 수 있습니다 ... 처음에는 순진 보이지만, 잠시 동안 그것에 대해 생각하는 동안 정말에 ... 일반적인 기능을 사용하여에 정확한 정보를 제공하는 모든 시나리오를 생각해보십시오 침몰에 대한 런타임 이 ISN 컴파일 타임에 아직 알려지지 않았습니다 (따라서 컴파일러 또는 T4 템플릿과 같은 코드 생성 유틸리티에 의해 자동 생성 될 수 있음) .

이제 이전 예제 세트의 요점은 일반 함수의 사소한 성가심을 보여주기위한 것이 었습니다 . 올바른 결과를 반환하는 모든 경우에 불필요하다는 것입니다 . 그러나 더 중요한 것은 아래의 예를 살펴보십시오. 다른 경우에 함수가 개체 실제 런타임 유형 이름을 반환 할 것으로 예상하는 경우 일반 함수의 결과가 실제로 잘못 되었음을 보여줍니다 . 이 함수는 실제로 조상 클래스, 인터페이스 또는 "객체"자체 일 수있는 참 값을 할당 할 수있는 유형의 이름 반환하도록 보장됩니다.

일반 함수가 잘못된 예

Stream ms = new MemoryStream();
IEnumerable str = "Hello";
IComparable i = 23;
object j = 1;

TypeNameLower(ms); //returns "stream" instead of "memorystream"
TypeNameLower(str); //returns "ienumerable" instead of "string"
TypeNameLower(i); //returns "icomparable" instead of "int32"
TypeNameLower(j); //returns "object" instead of "int32"
TypeNameLower<object>(true); //returns "object" instead of "bool"

모든 경우에 보시다시피 결과는 매우 잘못되었습니다. 자, 나는 마지막 두 줄이 요점을 보여주기 위해 약간 고안된 TypeNameLower(j)것이라고 인정합니다. 생각...)

문제는 함수가 실제로 전달되는 객체의 유형을 무시하고 일반 매개 변수 유형의 (컴파일 타임) 정보 만 사용하여 값을 반환한다는 것입니다.

더 나은 구현은 다음과 같습니다.

string TypeNameLower<T>(T obj) {
    Type t;
    if (obj == null)
        t = typeof(T);
    else 
        t = obj.GetType();
    return t.Name.ToLower();
}

이제이 함수는 객체가 null이 아닐 때마다 실제 런타임 유형의 이름을 반환하고 유형이이면 컴파일 시간 / 정의 된 유형으로 기본 설정됩니다 null.

중요한 것은이 함수는 일반 버전 없이도 사용할 수 있다는 것입니다 !! 그 결과 함수가를 반환 하지 않습니다null . 가장 일반적인 반환 값은 "object"입니다. 예 :

 object x = null; 
 string s = null;
 byte[] b = null;
 MyClass m = null;
 TypeNameLower(x); // returns "object"
 TypeNameLower(s); // returns "string"
 TypeNameLower(b); // returns "byte[]"
 TypeNameLower(m); // returns "myclass"

이것은 실제로 OP가 요청한 기능의 정의 된 목적과 더 일치 합니다. 즉, OP가 실제로 객체의 유형 이름이 null이 아니었다면 어떤 유형의 이름이 아니기 때문에 null을 반환하는 것은 적절한 대답 이 아닐 것입니다. typeof (null)이 정의되지 않았습니다.

C #을 하강의 모든 변수에서 System.Object값이 아니었다면 이렇게 정의에 의해, null그것은 것입니다Object그것은 런타임에 널 기준에 대해 판단 할 수있는 가장 많은 경우입니다.


// Uses the compiler's type inference mechanisms for generics to find out the type
// 'self' was declared with in the current scope.
static public Type GetDeclaredType<TSelf>(TSelf self)
{
    return typeof(TSelf);
}

void Main()
{
    // ...

    Foo bar;
    bar = null;

    Type myType = GetDeclaredType(bar);
    Console.Write(myType.Name);
}

인쇄물:

Foo

나는 이것을 비슷한 주제에 게시했습니다. 여러분에게 도움이되기를 바랍니다. ;-)


if (o == null) return "null";
else return o.GetType().Name.ToLower();

간단한 문제에 대한 간단한 해결책 :-p


다른 사람들이 언급했듯이 당신은 할 수 없습니다. 이것은 객체에 대한 순수 null 참조를 허용하는 언어에서 실제로 잘 알려진 문제입니다. 이를 해결하는 한 가지 방법은 "Null 개체 패턴"을 사용하는 것입니다. 기본 아이디어는 null빈 참조 를 사용하는 대신 "아무것도하지 않음"개체의 인스턴스를 할당하는 것입니다. 예를 들면 :

public class Circle
{
    public virtual float Radius { get; set; }

    public Circle(float radius)
    {
        Radius = radius;
    }
}

public class NullCircle : Circle
{
    public override float Radius 
    { 
        get { return float.NaN; }
        set { }
    }

    public NullCircle() { }
}

그런 다음 NullCircle대신 인스턴스를 전달할 수 있으며 null코드에서와 같이 유형을 테스트 할 수 있습니다.


내가 아는 한 당신은 할 수 없습니다. Null은 값이 없음을 나타내며 다른 유형에 대해 구별되지 않습니다.


널 문자열이 널 배열과 다르다는 개념은 없습니다. 함수 내에서 유형 이름을 확인할 수 없습니다.

보다 구체적으로, 참조 클래스의 인스턴스 (내부적으로)는 객체에 대한 유형 정보에 대한 "포인터"를 포함합니다. 입력이 null이면 해당 포인터가 없으므로 형식 정보가 존재하지 않습니다.


@Josh Einstein의 대답을 확장하십시오.

다음은 현재 null로 설정되어 있어도 변수 유형을 가져 오는 두 가지 확장 메서드입니다.

    /// <summary>
    /// Gets an object's type even if it is null.
    /// </summary>
    /// <typeparam name="T">The type of the object.</typeparam>
    /// <param name="that">The object being extended.</param>
    /// <returns>The objects type.</returns>
    public static Type GetTheType<T>(this T that)
    {
        return typeof(T);
    }

    /// <summary>
    /// Gets an object's type even if it is null.
    /// </summary>
    /// <param name="that">The object being extended.</param>
    /// <returns>The objects type.</returns>
    public static Type GetTheType(this object that)
    {
        if (that != null)
        {
            return that.GetType();
        }

        return null;
    }

Also, here are two simple unit tests to test the extension methods.

    /// <summary>
    /// Tests to make sure that the correct type is return.
    /// </summary>
    [Test(Description = "Tests to make sure that the correct type is return.")]
    public void Test_GetTheType()
    {
        var value = string.Empty;

        var theType = value.GetTheType();

        Assert.That(theType, Is.SameAs(typeof(string)));
    }

    /// <summary>
    /// Tests to make sure that the correct type is returned even if the value is null.
    /// </summary>
    [Test(Description = "Tests to make sure that the correct type is returned even if the value is null.")]
    public void Test_GetTheType_ReturnsTypeEvenIfValueIsNull()
    {
        string value = null;

        var theType = value.GetTheType();

        Assert.That(theType, Is.SameAs(typeof(string)));
    }

Edit Sorry, I forgot to mention that I was needing this exact same feature for a project I'm currently on. All credit still should go to @Josh Einstein :D


It is very frustrating that C# does not allow for such a determination to be made. And it is not akin to asking what cake you would have in an empty box - an object comprises two independent components - the "incarnation" of the object and the information on the class that was used to create the object. The fact that this information can't be accessed easily is an ommission on the part of the C#'s developers.

All you can do by way of determination is this rather crippling method:

void Method(object obj)
{
if(obj is int)
{
//obj is of the int type
}
else if(obj is SomeComplexType)
{
//obj is of the SomeComplexType type
}
}

So, you can see that even if the object is null, its type information is nevertheless travelling alongside the object, it is not lost, you just cant handily access it. But this is, to say the least, inconvenient.


If you have an object by itself (let's say as an input parameter to a method with type object), with no definition or generic type, there is no way to find the type. The reason is simple, you cannot send message to (invoke any method on) the object to ask about the type.

There could be some other workarounds, as you see in some answers, like using generic types. In that case, you're not asking the Null object, you are asking the generic type for its type.


Consider this code:

    public class MyClass1{}
    public class MyClass2{}

    public static void Test1()
    {
        MyClass1 one = null;
        MyClass2 two = (MyClass2) (object) one;

        one = new MyClass1();
        //invalid cast exception
        two = (MyClass2)(object) one;
    }

The runtime-type of a null instance is object, at least from a type-safety point of view.

참고URL : https://stackoverflow.com/questions/930147/how-to-get-the-lowercase-name-of-an-object-even-when-null-in-c-sharp

반응형