제네릭 클래스 또는 메서드의 멤버에서 T 유형을 가져 오는 방법은 무엇입니까?
클래스 또는 메서드에 일반 멤버가 있다고 가정 해 보겠습니다.
public class Foo<T>
{
public List<T> Bar { get; set; }
public void Baz()
{
// get type of T
}
}
클래스를 인스턴스화하면가 T
가 MyTypeObject1
되므로 클래스에 일반 목록 속성이 List<MyTypeObject1>
있습니다. 제네릭이 아닌 클래스의 제네릭 메서드에도 동일하게 적용됩니다.
public class Foo
{
public void Bar<T>()
{
var baz = new List<T>();
// get type of T
}
}
내 클래스 목록에 어떤 유형의 객체가 포함되어 있는지 알고 싶습니다. 따라서 호출 된 목록 속성 Bar
또는 지역 변수 baz
에는 어떤 유형이 포함 T
됩니까?
Bar[0].GetType()
목록에 요소가 없을 수 있으므로 할 수 없습니다 . 어떻게하니?
올바르게 이해하면 목록에 컨테이너 클래스 자체와 동일한 유형 매개 변수가 있습니다. 이 경우 :
Type typeParameterType = typeof(T);
object
유형 매개 변수로 사용하는 운이 좋은 상황에 있다면 Marc의 답변을 참조하십시오 .
(참고 : 나는 당신이 알고있는 모든 것을 믿고있어 object
나 IList
또는 유사한하고 목록이 실행시에 모든 유형이 될 수 있음)
라는 것을 알고 있다면 List<T>
:
Type type = abc.GetType().GetGenericArguments()[0];
또 다른 옵션은 인덱서를 보는 것입니다.
Type type = abc.GetType().GetProperty("Item").PropertyType;
새로운 TypeInfo 사용 :
using System.Reflection;
// ...
var type = abc.GetType().GetTypeInfo().GenericTypeArguments[0];
다음 확장 방법을 사용하면 반사없이 벗어날 수 있습니다.
public static Type GetListType<T>(this List<T> _)
{
return typeof(T);
}
또는 더 일반적 :
public static Type GetEnumeratedType<T>(this IEnumerable<T> _)
{
return typeof(T);
}
용법:
List<string> list = new List<string> { "a", "b", "c" };
IEnumerable<string> strings = list;
IEnumerable<object> objects = list;
Type listType = list.GetListType(); // string
Type stringsType = strings.GetEnumeratedType(); // string
Type objectsType = objects.GetEnumeratedType(); // BEWARE: object
시험
list.GetType().GetGenericArguments()
그것은 나를위한 일입니다. myList는 알려지지 않은 종류의 목록입니다.
IEnumerable myEnum = myList as IEnumerable;
Type entryType = myEnum.AsQueryable().ElementType;
전체 Type 변수가 필요하지 않고 유형을 확인하고 싶다면 쉽게 임시 변수를 만들고 사용할 수 있습니다.
T checkType = default(T);
if (checkType is MyClass)
{}
일반 목록의 반환 유형에 사용할 수 있습니다.
public string ListType<T>(T value)
{
var valueType = value.GetType().GenericTypeArguments[0].FullName;
return valueType;
}
이것을 고려하십시오. 동일한 방식으로 20 개의 입력 된 목록을 내보내는 데 사용합니다.
private void Generate<T>()
{
T item = (T)Activator.CreateInstance(typeof(T));
((T)item as DemomigrItemList).Initialize();
Type type = ((T)item as DemomigrItemList).AsEnumerable().FirstOrDefault().GetType();
if (type == null) return;
if (type != typeof(account)) //account is listitem in List<account>
{
((T)item as DemomigrItemList).CreateCSV(type);
}
}
The GetGenericArgument()
method has to be set on the Base Type of your instance (whose class is a generic class myClass<T>
). Otherwise, it returns a type[0]
Example:
Myclass<T> instance = new Myclass<T>();
Type[] listTypes = typeof(instance).BaseType.GetGenericArguments();
You can get the type of "T" from any collection type that implements IEnumerable<T> with the following:
public static Type GetCollectionItemType(Type collectionType)
{
var types = collectionType.GetInterfaces()
.Where(x => x.IsGenericType
&& x.GetGenericTypeDefinition() == typeof(IEnumerable<>))
.ToArray();
// Only support collections that implement IEnumerable<T> once.
return types.Length == 1 ? types[0].GetGenericArguments()[0] : null;
}
Note that it doesn't support collection types that implement IEnumerable<T> twice, e.g.
public class WierdCustomType : IEnumerable<int>, IEnumerable<string> { ... }
I suppose you could return an array of types if you needed to support this...
Also, you might also want to cache the result per collection type if you're doing this a lot (e.g. in a loop).
I use this extension method to accomplish something similar:
public static string GetFriendlyTypeName(this Type t)
{
var typeName = t.Name.StripStartingWith("`");
var genericArgs = t.GetGenericArguments();
if (genericArgs.Length > 0)
{
typeName += "<";
foreach (var genericArg in genericArgs)
{
typeName += genericArg.GetFriendlyTypeName() + ", ";
}
typeName = typeName.TrimEnd(',', ' ') + ">";
}
return typeName;
}
public static string StripStartingWith(this string s, string stripAfter)
{
if (s == null)
{
return null;
}
var indexOf = s.IndexOf(stripAfter, StringComparison.Ordinal);
if (indexOf > -1)
{
return s.Substring(0, indexOf);
}
return s;
}
You use it like this:
[TestMethod]
public void GetFriendlyTypeName_ShouldHandleReallyComplexTypes()
{
typeof(Dictionary<string, Dictionary<string, object>>).GetFriendlyTypeName()
.ShouldEqual("Dictionary<String, Dictionary<String, Object>>");
}
This isn't quite what you're looking for, but it's helpful in demonstrating the techniques involved.
public bool IsCollection<T>(T value){
var valueType = value.GetType();
return valueType.IsArray() || typeof(IEnumerable<object>).IsAssignableFrom(valueType) || typeof(IEnumerable<T>).IsAssignableFrom(valuetype);
}
Using 3dGrabber's solution:
public static T GetEnumeratedType<T>(this IEnumerable<T> _)
{
return default(T);
}
//and now
var list = new Dictionary<string, int>();
var stronglyTypedVar = list.GetEnumeratedType();
If you want to know a property's underlying type, try this:
propInfo.PropertyType.UnderlyingSystemType.GenericTypeArguments[0]
This is how i did it
internal static Type GetElementType(this Type type)
{
//use type.GenericTypeArguments if exist
if (type.GenericTypeArguments.Any())
return type.GenericTypeArguments.First();
return type.GetRuntimeProperty("Item").PropertyType);
}
Then call it like this
var item = Activator.CreateInstance(iListType.GetElementType());
OR
var item = Activator.CreateInstance(Bar.GetType().GetElementType());
Type:
type = list.AsEnumerable().SingleOrDefault().GetType();
'code' 카테고리의 다른 글
addEventListener 대 onclick (0) | 2020.10.02 |
---|---|
PostgreSQL 오류 : 치명적 : "사용자 이름"역할이 없습니다. (0) | 2020.10.02 |
이미지를 깔끔하게 빌드하기 위해 Docker를 강제하는 방법 (0) | 2020.10.02 |
변수를 사용하여 객체 속성에 동적으로 액세스 (0) | 2020.10.02 |
JavaScript에서 클래스를 정의하는 데 사용할 수있는 기술은 무엇이며 그 장단점은 무엇입니까? (0) | 2020.09.30 |