유형 C#로 과부하 메소드
-
05-07-2019 - |
문제
다음이 가능한지 궁금합니다. 익명 유형 (String, int, Decimal, CustomObject 등)을 수락하는 클래스를 만듭니다. 그런 다음 유형을 기반으로 다른 작업을 수행하는 과부하 메소드를 가지고 있습니다. 예시
class TestClass<T>
{
public void GetName<string>()
{
//do work knowing that the type is a string
}
public string GetName<int>()
{
//do work knowing that the type is an int
}
public string GetName<int>(int addNumber)
{
//do work knowing that the type is an int (overloaded)
}
public string GetName<DateTime>()
{
//do work knowing that the type is a DateTime
}
public string GetName<customObject>()
{
//do work knowing that the type is a customObject type
}
}
이제 getName 메소드를 호출 할 수 있었고 객체를 초기화했을 때 이미 유형을 통과했기 때문에 올바른 메소드가 발견되어 실행됩니다.
TestClass foo = new TestClass<int>();
//executes the second method because that's the only one with a "int" type
foo.GetName();
이것이 가능합니까 아니면 내가 꿈꾸는가?
해결책
당신이하려는 것은 다음과 같이 가능합니다.
class TestClass<T>
{
public string GetName<T>()
{
Type typeOfT = typeof(T);
if(typeOfT == typeof(string))
{
//do string stuff
}
}
}
이건 ~이다 가능하면, 당신은 제네릭의 목적을 물리 치고 있습니다. 제네릭의 요점은 유형의시기입니다 그렇지 않습니다 문제,이 경우 제네릭이 적절하다고 생각하지 않습니다.
다른 팁
C#에서는 전문화가 불가능합니다. C#에서 가장 가까운 것은 다음과 같습니다
public void Example() {
public static void Method<T>(T value) { ... }
public static void Method(int value){ ... }
public static void Method(string) { ... }
}
C# 컴파일러는 일반적인 방법보다 비 게 릭 방법을 선호합니다. 이는 int 매개 변수로 호출하면 int 오버로드와 일반적인 오버로드에 바인딩됩니다.
Example.Method(42); // Method(int)
Example.Method(new Class1()) // Method<T>(T)
메소드가 일반적으로 호출 될 때 적용되지 않기 때문에 이것은 당신을 물게 할 것입니다. 이 경우 유형에 관계없이 일반 과부하에 결합합니다.
public void Gotcha<T>(T value) {
Example.Method(value);
}
Gotcha(42); // Still calls Example.Method<T>()
C#에서 "전문화"는 C ++의 방식으로 불가능합니다. .NET 제네릭에서 일반 클래스 또는 방법u003CT> T의 가능한 모든 값에 대해 동일해야합니다. 이렇게하면 런타임이 두 가지 다른 참조 유형 (TestClass)을 최적화 할 수 있습니다.u003Cstring> 그리고 TestClass u003CListu003Cint> >, 동일한 기계 언어 코드를 공유하십시오. (다른 값 유형은 별도의 기계 코드를 얻지 만 여전히 전문화 할 수 없습니다.)
때로는 일반 인터페이스 또는 기본 클래스를 작성하는 데 도움이됩니다.
abstract class Base<T> {
public abstract T GetName();
// any common code goes here that does not require specialization
}
파생 수업에서 전문화 :
class IntVersion : Base<int> {
public override int GetName() { return 1; }
public int GetName(int addNumber) { ... }
}
class StringVersion : Base<string> {
public override string GetName() { return "foo"; }
}
class DateTimeVersion : Base<DateTime> {
public override DateTime GetName() { return DateTime.Now; }
}
아니요, 이것은 불가능합니다. 당신이하려는 것은 C#에서는 (슬프게도) C ++의 템플릿 전문화와 유사합니다.
if/else 또는 전환해야합니다
typeof(T)
특수 구현을 호출합니다.
그러나 T 유형을 클래스 (참조 값) 또는 구조물 (값) 또는 특정베이스 클래스의 서브 클래스로 제한 할 수 있습니다.
public Foo<T> DoBar<T>() where T : FooBase;
C#은 이러한 파견을 지원하지 않습니다.
그리고 이것은 모든 내부 <>가 메소드 서명의 일부가 아닌 한 메서드 과부하 (Error'TestClass '가 동일한 매개 변수 유형으로'getName이라는 멤버를 이미 정의하는 것)를 수행하는 올바른 방법이 아닙니다.
클래스 확장 방법을 사용하면 효과가 있습니까?
기본적으로 원하는 클래스에 메소드를 추가 한 다음 같은 방식으로 호출 할 수 있습니다.
namespace ExtensionMethods
{
public static class MyExtensions
{
public static int GetName(this String str)
{
...
}
}
}
사용을 사용합니다 :
myString.GetName();
수업에서 유형별 작업을 수행 해야하는 경우 수업이 일반적이지 않습니다. 처리하려는 각 유형에 대해 별도의 클래스를 만들어야 할 것입니다. 일반적인 이유가있는 기능이있는 경우 일반적인 기본 클래스에 넣을 수 있습니다.
An example:
abstract class TestClass<T>
{
public List<T> Items { get; set; }
// other generic (i.e. non type-specific) code
}
class IntTestClass : TestClass<int>
{
public string GetName()
{
// do work knowing that the type is an int
}
// other code specific to the int case
}
class StringTestClass : TestClass<string>
{
public string GetName()
{
// do work knowing that the type is a string
}
// other code specific to the string case
}
Bfree가 언급했듯이 IF 트리 또는 스위치 명령문 으로이 작업을 수행 할 수 있지만, 어느 시점에서는 시간이 지남에 따라 과부하 라이브러리를 키우는 경우 방법을 작성하고 .NET을 알아낼 수 있기를 바랍니다. .
.NET에서는 성능이 저렴하지만 반사 솔루션이 있습니다.
using System.Reflection;
...
public string DoSomething(object val)
{
// Force the concrete type
var typeArgs = new Type[] { val.GetType() };
// Avoid hard-coding the overloaded method name
string methodName = new Func<string, string>(GetName).Method.Name;
// Use BindingFlags.NonPublic instead of Public, if protected or private
var bindingFlags = BindingFlags.Public | BindingFlags.Instance;
var method = this.GetType().GetMethod(
methodName, bindingFlags, null, typeArgs, null);
string s = (string)method.Invoke(this, new object[] { val });
return s;
}
당신은 기본적으로 반사 프레임 워크를 통해 그 스위치 문을 연주하도록 지시합니다.