IT TIP

제네릭-여기서 T는 숫자입니까?

itqueen 2020. 12. 12. 12:53
반응형

제네릭-여기서 T는 숫자입니까?


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

일부 계산을 수행하기 위해 숫자 유형에 대해서만 제네릭 클래스를 만드는 방법을 찾으려고합니다.

내가 놓친 모든 숫자 유형 (int, double, float ...)에 대한 공통 인터페이스가 있습니까 ???

그렇지 않다면 그러한 클래스를 만드는 가장 좋은 방법은 무엇입니까?

최신 정보:

내가 달성하려는 가장 중요한 것은 T 유형의 두 변수 중 누가 더 큰지 확인하는 것입니다.


어떤 버전의 .NET을 사용하고 있습니까? .NET 3.5를 사용하는 경우 MiscUtil (무료 등) 일반 연산자 구현있습니다.

여기에는와 같은 메서드와 T Add<T>(T x, T y)다른 유형의 산술에 대한 다른 변형 (예 :)이 있습니다 DateTime + TimeSpan.

또한 이것은 모든 내장, 리프트 및 맞춤형 운영자를 위해 작동하며 성능을 위해 대리인을 캐시합니다.

이것이 까다로운 이유에 대한 추가 배경이 여기에 있습니다 .

dynamic(4.0) 종류가이 문제를 간접적으로도 해결 한다는 것을 알고 싶을 수도 있습니다.

dynamic x = ..., y = ...
dynamic result = x + y; // does what you expect

</에 대한 주석을 다시 >살펴보십시오. 실제로 연산자 필요 하지 않습니다 . 다음이 필요합니다.

T x = ..., T y = ...
int c = Comparer<T>.Default.Compare(x,y);
if(c < 0) {
    // x < y
} else if (c > 0) { 
    // x > y
}

IComparable<T>, IConvertibleIEquatable<T>인터페이스 같은 숫자 유형에 대한 일부 작업에 대한 인터페이스가 있습니다. 특정 기능을 얻기 위해 지정할 수 있습니다.

public class MaxFinder<T> where T : IComparable<T> {

   public T FindMax(IEnumerable<T> items) {
      T result = default(T);
      bool first = true;
      foreach (T item in items) {
         if (first) {
            result = item;
            first = false;
         } else {
            if (item.CompareTo(result) > 0) {
               result = item;
            }
         }
      }
      return result;
   }

}

대리자를 사용하여 유형별 작업으로 클래스를 확장 할 수 있습니다.

public class Adder<T> {

   public delegate T AddDelegate(T item1, T item2);

   public T AddAll(IEnumerable<T> items, AddDelegate add) {
      T result = default(T);
      foreach (T item in items) {
         result = add(result, item);
      }
      return result;
   }

}

용법:

Adder<int> adder = new Adder<int>();
int[] list = { 1, 2, 3 };
int sum = adder.AddAll(list, delegate(int x, int y) { return x + y; });

클래스에 대리자를 저장할 수도 있으며 특정 데이터 형식에 대한 대리자를 설정하는 다른 팩토리 메서드를 가질 수도 있습니다. 이런 식으로 유형별 코드는 팩토리 메서드에만 있습니다.


가장 가까운 것은 struct입니다. 코드에서 숫자 유형에 대해보다 광범위한 검사를 수행해야합니다.

public class MyClass<T> where T : struct
(...)

산술 연산을 위해 단일 인터페이스를 사용해야하므로 이렇게 할 수 없습니다. 이 특정 목적을 위해 IArithmetic 인터페이스를 추가하기 위해 Connect에서 많은 요청이 있었지만 지금까지 모두 거부되었습니다.

"계산기"인터페이스를 구현하는 멤버없이 구조체를 정의하여이 문제를 해결할 수 있습니다. 우리는 Pluto Toolkit 의 보간 제네릭 클래스에서이 접근 방식을 취했습니다 . 자세한 예를 들어, 여기에 "벡터"계산기 구현이 있어서 일반 보간 기가 벡터와 함께 작동 할 수 있습니다. 수레, 복식, 쿼터니언 등에 대한 유사한 것이 있습니다.


프레임 워크 BCL (기본 클래스 라이브러리)에서 많은 숫자 함수 (예 : System.Math의 함수)는 각 숫자 유형에 대해 오버로드를 가짐으로써이를 처리합니다.

BCL의 정적 Math 클래스에는 클래스의 인스턴스를 만들지 않고도 호출 할 수있는 정적 메서드가 포함되어 있습니다. 수업에서 똑같이 할 수 있습니다. 예를 들어 Math.Max에는 11 개의 오버로드가 있습니다.

public static byte Max(byte val1, byte val2);
public static decimal Max(decimal val1, decimal val2);
public static double Max(double val1, double val2);
public static short Max(short val1, short val2);
public static int Max(int val1, int val2);
public static long Max(long val1, long val2);
public static sbyte Max(sbyte val1, sbyte val2);
public static float Max(float val1, float val2);
public static ushort Max(ushort val1, ushort val2);
public static uint Max(uint val1, uint val2);
public static ulong Max(ulong val1, ulong val2);

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GenericPratice1
{
    public delegate T Del<T>(T numone, T numtwo)where T:struct;
    class Class1
    {
        public T Addition<T>(T numone, T numtwo) where T:struct
        {
            return ((dynamic)numone + (dynamic)numtwo);
        }
        public T Substraction<T>(T numone, T numtwo) where T : struct
        {
            return ((dynamic)numone - (dynamic)numtwo);
        }
        public T Division<T>(T numone, T numtwo) where T : struct
        {
            return ((dynamic)numone / (dynamic)numtwo);
        }
        public T Multiplication<T>(T numone, T numtwo) where T : struct
        {
            return ((dynamic)numone * (dynamic)numtwo);
        }

        public Del<T> GetMethodInt<T>(int ch)  where T:struct
        {
            Console.WriteLine("Enter the NumberOne::");
            T numone =(T) Convert.ChangeType((object)(Console.ReadLine()), typeof(T));
            Console.WriteLine("Enter the NumberTwo::");
            T numtwo = (T)Convert.ChangeType((object)(Console.ReadLine()), typeof(T));
            T result = default(T);
            Class1 c = this;
            Del<T> deleg = null;
            switch (ch)
            {
                case 1:
                    deleg = c.Addition<T>;
                    result = deleg.Invoke(numone, numtwo);
                    break;
                case 2: deleg = c.Substraction<T>;
                    result = deleg.Invoke(numone, numtwo);
                    break;
                case 3: deleg = c.Division<T>;
                    result = deleg.Invoke(numone, numtwo);
                    break;
                case 4: deleg = c.Multiplication<T>;
                    result = deleg.Invoke(numone, numtwo);
                    break;
                default:
                    Console.WriteLine("Invalid entry");
                    break;
            }
            Console.WriteLine("Result is:: " + result);
            return deleg;
        }

    }
    class Calculator
    {
        public static void Main(string[] args)
        {
            Class1 cs = new Class1();
            Console.WriteLine("Enter the DataType choice:");
            Console.WriteLine("1 : Int\n2 : Float");
            int sel = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine("Enter the choice::");
            Console.WriteLine("1 : Addition\n2 : Substraction\3 : Division\4 : Multiplication");
            int ch = Convert.ToInt32(Console.ReadLine());
            if (sel == 1)
            {
                cs.GetMethodInt<int>(ch);
            }
            else
            {
                cs.GetMethodInt<float>(ch);
            }

        }
    }
}

I don't believe you can define that using a generic type constraint. Your code could internally check your requirements, possibly using Double.Parse or Double.TryParse to determine if it is a number--or if VB.NET isn't out of the question then you could use the IsNumeric() function.

Edit: You can add a reference to Microsoft.VisualBasic.dll and call the IsNumeric() function from c#


You can not do it at compile time only. But you could put more constraints to weed out most of 'bad types' on your numeric type like below

class yourclass <T>where T: IComparable, IFormattable, IConvertible, IComparabe<T>, IEquatable<T>, struct {... In the end you would still have to check at runtime if your type is acceptable using object.GetType() method.

If only comparing, then IComparable<T> alone does the trick.

참고URL : https://stackoverflow.com/questions/1267902/generics-where-t-is-a-number

반응형