簡體   English   中英

C# - 修改特定於每種類型的數據結構的通用函數

[英]C# - Generic function to modify data structures specific to each type

我在使用泛型方面遇到了一些麻煩。

我想編寫一個給定類型的泛型函數,修改該類型的數據結構。

public static Dictionary<int, User> Users = new Dictionary<int, User>();
public static Dictionary<int, Item> Items = new Dictionary<int, Item>();
public static Dictionary<int, Store> Stores = new Dictionary<int, Store>();

public static void AddStuff<T>(T stuffToAdd)
{
    (What dict goes here?).TryAdd(stuffToAdd.Id, stuffToAdd)
}

我想稱之為:

AddStuff<User>(some_user);

因此,根據調用的類型,我必須弄清楚如何找到與該類型相關的數據結構並添加/刪除它的內容。 對我來說有什么想法?

編輯:我有20個這樣的詞典。

我在使用泛型方面遇到了一些麻煩。

是的,你是。 注意那種感覺。 它告訴你,你在濫用泛型。

我想編寫一個給定類型的泛型函數,修改該類型的數據結構。

我最好的建議是:不要那樣想。 泛型應該是通用的 這就是為什么他們被稱為泛型 如果您基於泛型類型參數執行不同的操作,那么您的代碼不是通用的

我想稱之為: AddStuff<User>(some_user);

別想了。

相反,編寫三個方法,並將它們稱為:

AddUserStuff(someUser);
AddItemStuff(someItem);
AddStoreStuff(someStore);

等等。 從邏輯上講,您有三種方法可以執行三種不同的操作,因此它們不是通用的 寫三種方法!

編輯:我有20個這樣的詞典。

寫出20種方法。 這並不難,而且比編寫一個有20個案例的“通用”方法更容易 ,因為它看起來很通用,但實際上並非如此。

看到你的用法AddStuff<User>(some_user) ,也可能是AddStuff(some_user) ,我沒有看到具有泛型的意義。 而不是使用無法編譯時驗證的東西(通用UserItemStore或其他東西)。 例如, AddStuff<string>("oops invalid usage")會產生運行時問題。 您也可以為每種類型使用重載。 您可以擁有私人幫助函數,例如Paul的擴展示例。

使用John Wu關於使用IHasId接口的想法,您可以創建一個這樣的私有助手:

private static void AddStuff<T>(Dictionary<int, T> dict, T stuffToAdd)
    where TValue  : IHasId
{
    dict.TryAdd(stuffToAdd.Id, stuffToAdd)
}

您可以使用它並創建簡單的重載:

public static void AddStuff(User user) => AddStuff(Users, user);
public static void AddStuff(Item item) => AddStuff(Items, item);
public static void AddStuff(Store store) => AddStuff(Stores, store);

您可以使用if / else if或switch(僅限C#7)來完成此操作。

public static void AddStuff<T>(T stuffToAdd)
{
    switch (stuffToAdd)
    case User:
        Users.TryAdd(stuffToAdd.Id, stuffToAdd);
    // More cases
}

PS:在移動和公共汽車上。 因此,請進行必要的更正以使其編譯等。另外正如其他人指出的那樣,您實際上並不需要通用。 所以不要使用我在這里展示的內容!

為了能夠訪問Id屬性,您需要一個通用接口和一個類型約束。 在我的示例中,我包含一個IHasId接口,因此所有域類型都具有該ID可用。

要選擇字典,您只需要將它們排列在更大的字典中。 在我的例子中,我稱之為dictionaries

//This interface allows you to specify a type constraint so AddStuff can use the Id property
public interface IHasId
{
    int Id { get; }
}

public class User  : IHasId { public int Id { get; set; } }
public class Item  : IHasId { public int Id { get; set; } }
public class Store : IHasId { public int Id { get; set; } }

public class Program
{
    public static Dictionary<int, User> Users = new Dictionary<int, User>();
    public static Dictionary<int, Item> Items = new Dictionary<int, Item>();
    public static Dictionary<int, Store> Stores = new Dictionary<int, Store>();

    //This "outer" dictionary will allow AddStuff to look up the right dictionary based on the type.
    public static Dictionary<Type,IDictionary> dictionaries = new Dictionary<Type,IDictionary>
    {
        { typeof(User ), Users },
        { typeof(Item ), Items }, 
        { typeof(Store), Stores}
    };

    public static void AddStuff<TValue>(TValue stuffToAdd) where TValue  : IHasId
    {
        IDictionary d = dictionaries[typeof(TValue)] as Dictionary<int, TValue>;
        d.Add(stuffToAdd.Id, stuffToAdd);
    }

    public static void Main()
    {
        AddStuff( new User  { Id = 1} );
        AddStuff( new User  { Id = 2} );
        AddStuff( new Item  { Id = 3} );
        AddStuff( new Item  { Id = 4} );
        AddStuff( new Store { Id = 5} );
        AddStuff( new Store { Id = 6} );

        Console.WriteLine("Users:  " + string.Join(",", Users.Select( u => u.Value.Id )));
        Console.WriteLine("Items:  " + string.Join(",", Items.Select( i => i.Value.Id )));
        Console.WriteLine("Stores: " + string.Join(",", Stores.Select( s => s.Value.Id )));
    }
}

輸出:

Users:  1,2
Items:  3,4
Stores: 5,6

鏈接到有效的DotNetFiddle示例

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM