如何使用泛型方法中的泛型列表的属性 – c#

huangapple go评论61阅读模式
英文:

How to use props of generic list which is part of generic method - c#

问题

在我的小应用程序中,我想要重用用于计算价格的方法,以用于几种不同的对象,这让我觉得它可能是通用方法。有时它将接收主要产品并返回它们,有时它将接收文章并返回它们,有时它将接收类别文章并返回它们。

所以为了避免编写3个几乎相同的方法,我考虑制作它成为通用方法,类似于这样:

private async Task<List<T>> GetArticlesPolicyAsync<T>(List<T> articles, Guid externalCompanyId, CancellationToken cancellationToken)
{
    var externalArticleIds = articles.Select(x => x.ExternalArticleId).ToArray();

    var externalCategoryIds = articles.Select(x => x.ExternalCategoryId).ToArray();

    var externalSubCategoryIds = articles.Select(x => x.ExternalSubCategoryId).ToArray();

    var externalBrandIds = articles.Select(x => x.ExternalBrandId).ToArray();

    var pricePolicyItems = new List<ExternalPricePolicyItemGetDto>()....以及更多....
}

我接收作为参数 'articles' 的每个列表都一定会包含这4个属性:

  • ExternalArticleId
  • ExternalCategoryId
  • ExternalSubCategoryId
  • ExternalBrandId

但不幸的是,这是我看到的错误:

错误 CS1061:'T' 不包含定义 'ExternalArticleId' 的内容,
并且找不到接受类型为 'T' 的第一个参数的可访问扩展方法 'ExternalArticleId'
(是否缺少 using 指令或程序集引用?)

我不确定这种情况是否可以完全通用?

任何帮助都将非常棒。

提前感谢,

干杯

英文:

in my small app I would like to reuse method used for prices calculation for few different objects, that gives me an idea it could be generic method, sometimes it will receive main-products and return them, sometimes it will receive articles and return them, sometimes it will receive category-articles and returned them.

So to avoid writing 3 almost identical methods, I was thinking about making it generic. Something like this:

private async Task&lt;List&lt;T&gt;&gt; GetArticlesPolicyAsync&lt;T&gt;(List&lt;T&gt; articles, Guid externalCompanyId, CancellationToken cancellationToken)
{
	var externalArticleIds = articles.Select(x =&gt; x.ExternalArticleId).ToArray();

	var externalCategoryIds = articles.Select(x =&gt; x.ExternalCategoryId).ToArray();

	var externalSubCategoryIds = articles.Select(x =&gt; x.ExternalSubCategoryId).ToArray();

	var externalBrandIds = articles.Select(x =&gt; x.ExternalBrandId).ToArray();

	var pricePolicyItems = new List&lt;ExternalPricePolicyItemGetDto&gt;().... and so on....

Every sigle list that I receive as a prop 'articles' will definately contain this 4 props:

  • ExternalArticleId

  • ExternalCategoryId

  • ExternalSubCategoryId

  • ExternalBrandId

but unfortunately this is the error I am seeing:

> Error CS1061 'T' does not contain a definition for 'ExternalArticleId'
> and no accessible extension method 'ExternalArticleId' accepting a
> first argument of type 'T' could be found (are you missing a using
> directive or an assembly reference?)

I am not sure if this scenario can be generic 100% ?

Any kind of help would be awesome

Thanks in advance,

Cheers

答案1

得分: 1

为了使泛型工作,泛型类型必须受限于具有你要访问的所有属性的类型(否则你只能将T成员视为object类型)。

一种方法是创建一个定义这些属性的接口:

interface ExternalStuff
{
    int ExternalArticleId { get; set; }
    int ExternalCategoryId { get; set; }
    int ExternalSubCategoryId { get; set; }
    int ExternalBrandId { get; set; }
}

然后,对于所有实现这些属性的类型,你需要在类定义后添加 : ExternalStuff,以指定它们满足新接口的要求:

class Article : ExternalStuff
{
    // ...
}

class MainProduct : ExternalStuff
{
    // ...
}

class CategoryArticle : ExternalStuff
{
    // ...
}

最后,你需要通过在方法声明的末尾添加 where T : ExternalStuff 来将泛型类型 T 限制为这个接口,这告诉编译器只能使用实现该接口的项,并保证你访问的属性将是这些对象的成员:

private async Task<List<T>> GetArticlesPolicyAsync<T>(List<T> articles, 
    Guid externalCompanyId, CancellationToken cancellationToken) 
    where T : ExternalStuff
{
    var externalArticleIds = articles.Select(x => x.ExternalArticleId).ToArray();
    var externalCategoryIds = articles.Select(x => x.ExternalCategoryId).ToArray();
    var externalSubCategoryIds = articles.Select(x => x.ExternalSubCategoryId).ToArray();
    var externalBrandIds = articles.Select(x => x.ExternalBrandId).ToArray();
    // 等等...
}

你可以在这里阅读更多关于约束的信息:类型参数的约束(C# 编程指南)

英文:

To make this work with generics, the generic type must be constrained to a type that has all the properties you want to access (otherwise you only have access to members T as an object type).

One way to do this is to create an interface that defines these properties:

interface ExternalStuff
{
    int ExternalArticleId { get; set; }
    int ExternalCategoryId { get; set; }
    int ExternalSubCategoryId { get; set; }
    int ExternalBrandId { get; set; }
}

Then for all the types that implement these properties, you would need to specify that they fulfill the requirements of the new interface by adding : ExternalStuff after the class definition:

// You shouldn&#39;t have to do anything else inside the classes since you said 
// all the types already implemented the properties defined in the interface

class Article : ExternalStuff
{
    // ...
}

class MainProduct : ExternalStuff
{
    // ...
}

class CategoryArticle : ExternalStuff
{
    // ...
}

And finally you need to constrain the generic type T to this interface by adding where T : ExternalStuff at the end of the method declaration, which tells the compiler that only items that implement the interface can be used, and guarantees that the properties you're accessing will be members of those objects:

private async Task&lt;List&lt;T&gt;&gt; GetArticlesPolicyAsync&lt;T&gt;(List&lt;T&gt; articles, 
    Guid externalCompanyId, CancellationToken cancellationToken) 
    where T : ExternalStuff
{
    var externalArticleIds = articles.Select(x =&gt; x.ExternalArticleId).ToArray();
    var externalCategoryIds = articles.Select(x =&gt; x.ExternalCategoryId).ToArray();
    var externalSubCategoryIds = articles.Select(x =&gt; x.ExternalSubCategoryId).ToArray();
    var externalBrandIds = articles.Select(x =&gt; x.ExternalBrandId).ToArray();
    // etc...
}

You can read more about contraints here: Constraints on type parameters (C# Programming Guide)

答案2

得分: 0

你需要做的是创建一个接口,用于保存类型 T 的共同属性,例如:

public interface IArticles
{
    int ExternalArticleId;

    int ExternalCategoryId;

    int ExternalSubCategoryId;

    int ExternalBrandId;
}

然后在泛型类型 T 中使用 where 子句定义一个约束。

Task<List<T>> GetArticlesPolicyAsync<T>(List<T> articles, Guid externalCompanyId, CancellationToken cancellationToken)
where T : IArticles
{
    var externalArticleIds = articles.Select(x => x.ExternalArticleId).ToArray();

    var externalCategoryIds = articles.Select(x => x.ExternalCategoryId).ToArray();

    var externalSubCategoryIds = articles.Select(x => x.ExternalSubCategoryId).ToArray();

    var externalBrandIds = articles.Select(x => x.ExternalBrandId).ToArray();

    var pricePolicyItems = new List<ExternalPricePolicyItemGetDto>().... 等等.... 

希望这有所帮助。祝好。

英文:

What u need to do is to create an interface that holds the properties that are common for type T for example:

public interface IArticles
{
    int ExternalArticleId;

    int ExternalCategoryId;

    int ExternalSubCategoryId;

    int ExternalBrandId;
}

then define a constrain in the generic type T using the where clause.

Task&lt;List&lt;T&gt;&gt; GetArticlesPolicyAsync&lt;T&gt;(List&lt;T&gt; articles, Guid externalCompanyId, CancellationToken cancellationToken)
where T : IArticles
{
    var externalArticleIds = articles.Select(x =&gt; x.ExternalArticleId).ToArray();

    var externalCategoryIds = articles.Select(x =&gt; x.ExternalCategoryId).ToArray();

    var externalSubCategoryIds = articles.Select(x =&gt; x.ExternalSubCategoryId).ToArray();

    var externalBrandIds = articles.Select(x =&gt; x.ExternalBrandId).ToArray();

    var pricePolicyItems = new List&lt;ExternalPricePolicyItemGetDto&gt;().... and so on....

Hope this helps.
Regards.

huangapple
  • 本文由 发表于 2023年3月4日 01:59:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/75630421.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定