문제

데이터 객체가 있지만이 객체는 여러 유형의 데이터 중 하나를 보유 할 수 있습니다.

class Foo
{
    int intFoo;
    double doubleFoo;
    string stringFoo;
}

이제 액세서를 만들고 싶습니다. 이 데이터를 얻는 방법. 분명히 여러 액세서를 만들 수 있습니다.

public int GetIntFoo();
public double GetDoubleFoo();
public string GetStringFoo();

또는 여러 속성을 만들 수 있습니다

public int IntFoo { get; set; }
public double DoubleFoo { get; set; }
public string StringFoo { get; set; }

나는 이것이 아주 좋은 디자인이라는 것이 아닙니다. 클라이언트 코드는 유형에 대해 더 걱정해야합니다. 또한,이 클래스에는 단일 값 만 필요하며 위는 각 유형 중 하나를 동시에 할당 할 수 있습니다. 안좋다.

한 가지 옵션은 제네릭을 사용하는 것입니다.

class Foo<T>
{
    public T TheFoo { get; set; }
}

그러나 이것은 foo를 만들지 않고 foo를 만듭니다.u003CT> . 각각마다 다른 유형이므로 실제로 동일한 유형으로 사용할 수 없습니다.

나는 foo를 도출 할 수 있습니다u003CT> Foobase에서 모든 것을 Foobase 's로 취급하지만 데이터에 액세스하는 문제로 돌아 왔습니다.

다른 제네릭 옵션은 다음과 같은 것을 사용하는 것입니다.

class Foo
{
    string stringRepresentationOfFoo;
    public T GetFoo<T>() { return /* code to convert string to type */ }
}

물론 문제는 모든 종류의 T가 통과 될 수 있다는 것입니다. 솔직히 말해서 조금 바쁩니다.

나는 또한 값을 상자에 넣고 객체를 반환 할 수 있지만 유형 안전은 없습니다.

이상적으로는 모든 Foo를 동일하게 취급하고 싶지만 StringFoo가 없으면 Stringfoo에 대한 참조를 컴파일 할 수 없도록 유형 안전을 원합니다.

Foo foo = new Foo("Foo");
string sFoo = foo.Value;  // succeeds.
&nbsp;
Foo foo = new Foo(0);
int iFoo = foo.Value; // succeeds
string sFoo = foo.Value; // compile error

아마도 이것은 불가능할 것입니다. 그리고 나는 약간의 타협을해야 할 것입니다.

어떤 아이디어?

편집하다:

Daniel이 지적했듯이 런타임 유형의 컴파일 시간 점검은 실용적이지 않습니다.

내가 여기서하고 싶은 일을하기위한 최선의 선택은 무엇입니까? 즉, 모든 foo를 동일하게 취급하지만 여전히 비교적 제정신 접근 메커니즘을 가지고 있습니까?

edit2 :

값을 다른 유형으로 변환하고 싶지 않습니다. 값에 대한 올바른 유형을 반환하고 싶습니다. 즉, 두 배라면 int를 반환하고 싶지 않습니다.

도움이 되었습니까?

해결책

변수를 Get의 매개 변수로 전달하는 것은 어떻습니까? 이와 같이:

int i = foo.get(i);

그런 다음 수업에는 다음과 같은 것이 있습니다.

public int get(int p) {
    if(this.type != INTEGER) throw new RuntimeException("Data type mismatch");
    return this.intVal;
}

public float get(float p) {
    if(this.type != FLOAT) throw new RuntimeException("Data type mismatch");
    return this.floatVal;
}

이런 종류의 유형은 내부를 확인하는 유형을 바꿉니다. Foo가 어떤 유형의 보유가 보유하고 있는지 확인하는 대신 Foo가 원하는 유형을 확인하십시오. 해당 유형을 줄 수 있다면, 그렇지 않으면 런타임 예외를 던집니다.

다른 팁

나는 이것이 효과가 있다고 생각하지 않습니다 (원하는 컴파일러 오류를 제공합니다)

당신은 이것을 무엇을하기를 원하십니까 :

Foo bar = (new Random()).Next(2) == 0 ? new Foo("bar") : new Foo(1);
int baz = bar.Value;

컴파일러 오류입니까?

나는 "그들 모두를 동일하게 처리"(적어도 당신이 설명한 방식)과 "컴파일 타임 오류"는 상호 배타적이라고 생각합니다.

어쨌든, 나는 "가장 좋은 방법"이 제네릭과 상속 사이의 타협이 될 것이라고 생각합니다. 당신은 a를 정의 할 수 있습니다 Foo<T> 그것은 foo의 서브 클래스입니다. 그런 다음 여전히 컬렉션을 가질 수 있습니다 Foo.

abstract public class Foo
{
  // Common implementation

  abstract public object ObjectValue { get; }
}

public class Foo<T> : Foo
{
   public Foo(T initialValue)
   {
      Value = initialValue;
   }

   public T Value { get; set; }

   public object ObjectValue
   { 
      get { return Value; }
   }
}

많은 시스템은 .NET Frameworks Base Object에 toString () 메소드가있는 것처럼 대체 유형을 반환하기 위해 도우미 방법을 사용합니다.

각 객체에 가장 적합한 기본 유형을 선택하고 다른 경우 방법을 제공합니다.

예를 들어

class Foo{
    public Int32 Value { get; set; }
    public Byte ToByte() { return Convert.ToByte(Value); }
    public Double ToDouble() { return (Double)Value; }
    public new String ToString() { return Value.ToString("#,###"); }
}

한 가지는 클래스의 내부 상태에 모든 유형을 저장하는 것이고 다른 하나는 외부에서 노출하는 것입니다. 수업을 작성할 때 실제로 그 행동에 대한 계약을 선언하는 것입니다. 작성 방식은 클래스를 사용할 때 클라이언트 코드의 모습에 큰 영향을 미칩니다.

예를 들어, 상상할 수 있습니다 인터페이스 당신은 유형을 CLR 유형으로 동등한 값으로 변환 할 수 있다고 말합니다.

또한 값 클래스가 계산 결과를 저장하는 데 사용되는 구현, 문자열, 이중, int 또는 부울을 나타내는 결과를 보았습니다. 그러나 문제는 클라이언트 코드가 Enum {String, Integer, Double, Boolean}의 값을 확인한 다음 값을 캐스트해야한다는 것입니다. ) 또는 특정 용도, 가치, ValueInt, ValueBoolean Getters를 사용하십시오.

그냥 사용하지 않는 이유는 무엇입니까? string, double 그리고 int?


수집에 대한 정보 후 : 사용은 어떻습니까 object? 어쨌든 유형 등을 확인해야합니다. 그리고 당신을 도울 수 있도록 is 그리고 as 운영자. 그리고 열거 가능 .cast 메소드, 또는 더 나은 열거 가능. ofType 방법.

사실,이 수업의 목적은 무엇입니까? 가장 큰 문제는 적어도 SRP (단일 책임 원리)를 깨는 디자인 인 것 같습니다.

그럼에도 불구하고, 내가 올바르게 읽고 있다면 컨테이너에 값을 저장하고 컨테이너를 클라이언트에 전달하고 값을 유형으로 검색하고 싶습니다.

이 접근법을 사용하면 제안서를 사용할 수 있습니다.

namespace Project1 {
public class Class1 {
    static int Main(string[] args) {
        Foo a = new Foo();
        a.SetValue(4);
        Console.WriteLine(a.GetValue<int>());

        Foo b = new Foo();
        a.SetValue("String");
        Console.WriteLine(a.GetValue<string>());

        Console.ReadLine();

        return 0;
    }
}


class Foo {
    private object value; // watch out for boxing here!
    public void SetValue(object value) {
        this.value = value;
    }

    public T GetValue<T>() {
        object val = this.value;
        if (val == null) { return default(T); } // or throw if you prefer
        try {
            return (T)val;
        }
        catch (Exception) {
            return default(T);
            // cast failed, return default(T) or throw
        }
    }
}
}

그러나이 경우 단순히 데이터를 객체로 전달하고 직접 캐스트하지 않는 이유는 무엇입니까?

필요에 따라 "C#"에서 "PHP"를 시도 할 수도 있습니다.

namespace Project1 {
public class Class1 {
    static int Main(string[] args) {
        MyInt a = 1;
        MyInt b = "2";

        Console.WriteLine(a + b); // writes 3

        Console.ReadLine();

        return 0;
    }
}


class MyInt {
    private int value;

    public static implicit operator int(MyInt container) {
        return container.value;
    }

    public static implicit operator MyInt(int value) {
        MyInt myInt = new MyInt();
        myInt.value = value;
        return myInt ;
    }

    public static implicit operator MyInt(string stringedInt) {
        MyInt myInt = new MyInt();
        myInt.value = int.Parse(stringedInt);
        return myInt;
    }
}
}

죄송합니다. 전제를 사지 않습니다. 데이터가 모두 같은 목적을 갖는 경우 모두 동일한 유형을 가져야합니다. 여러 웹 서비스 중 하나에 의해 반환 된대로 현재 온도를 유지하기위한 클래스를 고려하십시오. 모든 서비스는 온도를 Centighade에서 반환합니다. 그러나 하나는 int로 돌아오고, 하나는 더블로 돌아오고, 하나는 그것을 문자열로 반환합니다.

세 가지 다른 유형이 아닙니다. 하나의 유형입니다 - 더블. 비-가우블 리턴을 두 배로 변환하면 온도가있는 것 (또는 아마도 플로트)입니다.

일반적으로 한 가지를 여러 가지 표현을 가지고 있다면 여전히 여러 가지가 아니라 한 가지입니다. 다중 표현을 하나로 변환하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top