[英]Unable to compile while use the Generics List<T> in C#
I have two different classes.我有两个不同的课程。 And, those two different classes have multiple properties as well.而且,这两个不同的类也有多个属性。 Consider the following two example classes,考虑以下两个示例类,
public Class1{
public string Key;
public string value;
}
public Class2{
public string Key;
public string value;
}
Note: For example, I added the class like above.注意:例如,我像上面一样添加了 class。 But, in reality, the two classes should have different values with the same name.但是,实际上,这两个类应该具有相同名称的不同值。
These classes should be a member of the list like below,这些类应该是如下列表的成员,
List<Class1> list1 = new List<Class1>();
List<Class2> list2 = new List<Class2>();
So, to process these list I need a two different functions something like below,所以,要处理这些列表,我需要两个不同的函数,如下所示,
private string GetStrValue(List<Class1> values)
{
string toRet = string.Empty;
if (values == null)
return toRet;
foreach (Class1 val in values)
{
if (!string.IsNullOrWhiteSpace(val.Key)) {
toRet = val.value;
break;
}
}
return toRet;
}
And, the similar function to process the Int class as well.并且,类似的 function 也可以处理 Int class。 So, I planned to use the generic.所以,我打算使用泛型。 I have written the code like below,我已经编写了如下代码,
private string GetValue<T>(List<T> listValue)
{
string toRet = string.Empty;
if (listValue == null)
return toRet;
foreach (T iter in listValue)
{
if (!string.IsNullOrWhiteSpace(iter.Key)) {
toRet = val.Name;
break;
}
}
return toRet;
}
But, the code does not compile.但是,代码无法编译。 I'm facing the below error.我面临以下错误。
Severity Code Description Project File Line Suppression State
Error CS1061 'T' does not contain a definition for 'Name' and no accessible extension method 'Name' accepting a first argument of type 'T' could be found (are you missing a using directive or an assembly reference?)
It would be much-appreciated anyone helping on this.任何对此提供帮助的人都会非常感激。
Thank you,谢谢,
You have said "This code works for every type T" and yet you expect your Type T to have a property called Name, which many many types do not have.您已经说过“此代码适用于每种类型 T”,但您希望您的类型 T 有一个名为 Name 的属性,而许多类型都没有。 Generics do not work that way. Generics 不能那样工作。
If you want to do something with your instance of type T that requires it to have certain properties, you need to tell the compiler that T is constrained to types that have those properties.如果你想对你的类型 T 的实例做一些需要它具有某些属性的事情,你需要告诉编译器 T 被限制为具有这些属性的类型。
In your case you will need to write an interface common to both of your classes and the add that interface to your generic T definition.在您的情况下,您将需要编写一个对两个类都通用的接口,并将该接口添加到您的通用 T 定义中。
This is well explained (including a good example with code) in the Microsoft documentation here这在此处的 Microsoft 文档中得到了很好的解释(包括一个很好的代码示例)
You have 2 options interface
or father class
.您有 2 个选项interface
或father class
。 Bot 2 ways require where T: interfaceName
or where T: fatherClassName
syntax Bot 2 方式需要where T: interfaceName
或where T: fatherClassName
语法
For example with interface:以接口为例:
public interface IClass
{
string Key { get; set; }
string Name { get; set; }
string value { get; set; }
}
public class Class1 : IClass
{
public string Key { get; set; }
public string value { get; set; }
public string Name { get; set; }
}
public class Class2 : IClass
{
public string Key { get; set; }
public string value { get; set; }
public string Name { get; set; }
}
Then your generic class would be那么您的通用 class 将是
private string GetValue<T>(List<T> listValue) where T : IClass
{
string toRet = string.Empty;
if (listValue == null)
return toRet;
foreach (T val in listValue)
{
if (!string.IsNullOrWhiteSpace(val.Key))
{
toRet = val.Name;
break;
}
}
return toRet;
}
You can make it completely generic using Reflection (refer Reflection | PropertyInfo ).您可以使用 Reflection 使其完全通用(请参阅Reflection | PropertyInfo )。 This way you would be able to handle any classes coming to you.这样,您将能够处理任何给您上课的课程。 Please refer to the sample code below:请参考下面的示例代码:
private string GetValue<T>(List<T> listValue)
{
string toRet = string.Empty;
if (listValue == null)
return toRet;
PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
//Since you have mentioned all classes will have "Key" and "Value" and you need to use that only
//To make it completely generic you can maybe get this as input to this function
PropertyInfo keyProperty = properties.FirstOrDefault(x => x.Name.Equals("Key", StringComparison.OrdinalIgnoreCase));
PropertyInfo valueProperty = properties.FirstOrDefault(x => x.Name.Equals("Value", StringComparison.OrdinalIgnoreCase));
if (keyProperty == null || valueProperty == null)
return toRet;
foreach (T iter in listValue)
{
var keyData = keyProperty.GetValue(iter, null);
if (keyData != null && !string.IsNullOrWhiteSpace(keyData.ToString()))
{
toRet = valueProperty.GetValue(iter, null).ToString();
break;
}
}
return toRet;
}
As nvoigt mentioned, in this situation we have to use ' Interface ' concept.正如nvoigt提到的,在这种情况下我们必须使用“接口”概念。
Define your classes and interface as below:定义你的类和接口如下:
public interface IKeyValue
{
public string Key { get; set; }
public string Value { get; set; }
}
public class A : IKeyValue
{
public string Key { get; set; }
public string Value { get; set; }
//other properties...
}
public class B : IKeyValue
{
public string Key { get; set; }
public string Value { get; set; }
//other properties...
}
And your method which is going to use 'Key' and 'Value' should be like this:你的方法将使用'Key'和'Value'应该是这样的:
private string GetValue<T>(List<T> listValue) where T: IKeyValue
{
string toRet = string.Empty;
if (listValue == null)
return toRet;
foreach (T iter in listValue)
{
if (!string.IsNullOrWhiteSpace(iter.Key))
{
toRet = iter.Value;
break;
}
}
return toRet;
}
'where T: IKeyValue' in method definition means type T is ' IKeyValue ' that cause I can access the ' Key ' and ' Value ' in context (just those that are in IKeyValue interface)方法定义中的“其中 T:IKeyValue”表示类型 T 是“ IKeyValue ”,这导致我可以在上下文中访问“ Key ”和“ Value ”(仅在IKeyValue接口中的那些)
This is how you can use it:这是您可以使用它的方式:
List<IKeyValue> keyValues = new List<IKeyValue>
{new A{Key="a",Value="b"}, new B{Key="x",Value="y"}};
List<A> listA = new List<A>
{ new A { Key = "h", Value = "b" }, new A { Key = "u", Value = "m" } };
List<B> listB = new List<B>
{ new B { Key = "h", Value = "b" }, new B { Key = "u", Value = "m" } };
string resultListInterface = GetValue(keyValues); //valid
string resultListA = GetValue(listA); //valid
string resultListB = GetValue(listB); //valid
For naming convention I change property name from ' value ' to ' Value '对于命名约定,我将属性名称从“值”更改为“值”
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.