簡體   English   中英

如何創建C#泛型方法

[英]How to create a C# generic method

我有一種方法可以將粘貼復制到許多類中。 該方法將模型合並到IdNameViewModel中。 如何使用此方法創建一個類,我可以在存儲庫模型中傳遞該類並獲取該模型的IdName列表?

注意:ProjectValue是例如我要傳遞的模型/類,但實際上它可以是包含id和name屬性的任何模型/類。

private IdNameVM HydrateEntityToVM(ProjectValue projectValue)
{
    if (projectValue == null) return null;

    return new IdNameVM()
    {
        Id = projectValue.Id,
        Name = projectValue.Name
    };
}

這是我根據以下答案得出的結果:

public class GenericHydrateIdName<TModel> where TModel : INameId
    {
        public IdNameVM HydrateEntityToVM(TModel model)
        {
            if (model == null) return null;

            return new IdNameVM()
            {
                Id = model.Id,
                Name = model.Name
            };
        }
    }
}

請注意,如果有人在追隨,上面的類會導致過多的工作,並且違反了“清潔代碼原則”。 我在下面使用了擴展方法。

基本上,我看到的最好的類型安全的方法是擁有一個接口。

interface INameId
{
    int Id { get; set; }
    string Name { get; set; }
}

您可以在要使用它的每個類中使用此接口。根據您當前的用法,我建議使用擴展功能

static class VMExtensions
{

    public static IdNameVM HydrateEntityToVM<TModel>(this TModel model)
        where TModel : INameId
    {
        if (model == null) return null;

        return new IdNameVM()
        {
            Id = model.Id,
            Name = model.Name
        };
    }

    // update: without generics as Marcus Höglund pointed out
    public static IdNameVM HydrateEntityToVM2(this INameId model)
    {
        if (model == null) return null;

        return new IdNameVM()
        {
            Id = model.Id,
            Name = model.Name
        };
    }

    static void Test()
    {
        var model = new ProjectValue();
        var model2 = new AnotherModel();

        var viewModel = model2.HydrateEntityToVM();
        var viewModel2 = model2.HydrateEntityToVM();

    }

}

如果您不想將接口添加到所有模型中,則可以使用反射(但請注意,這確實很慢)。

更新資料

正如Marcus所指出的,在這種情況下,在函數中使用泛型沒有任何實際意義。 您可以使用直接使用該接口的HydrateEntityToVM2實現。 但是,在將來,如果要使用IdNameVM<TModel>類的東西,以便在需要時仍可以訪問原始模型,則具有泛型的HydrateEntityToVM函數將很有幫助。

這些是C#的基礎。 看一下這個鏈接

class MyClass<T> where T : ProjectValue
{
    private IdNameVM HydrateEntityToVM(T projectValue)
    {
        if (projectValue == null) return null;

        return new IdNameVM()
        {
            Id = projectValue.Id,
            Name = projectValue.Name
        };
    }
}

如果您不知道模型的抽象(但請注意,此方法可以使用任何包含id和name公共屬性的對象),請嘗試以下操作:

public void SomeGenericMethod<T>(T model) where T : class
{
    if (model == null) return null;

    var propId = model.GetType().GetProperty("id");
    var propName = model.GetType().GetProperty("name");
    if (propId == null || propName == null)
        return;


    return new IdNameVM()
    {
        Id = model.Id,
        Name = model.Name
    };
}

創建通用方法時,必須牢記一些規則

  1. 您將要支持什么類型
  2. 會有什么結果
  3. 解決方案之間必須有奇異之處

讓我們以上述示例為例:您需要一個名稱為HydrateEntityToVM的通用方法。 第一步是方法的聲明語法以及從T類型的Strong Type進行對象強制轉換。

這里要注意的一點是,您正在傳遞T類型,並且希望結果始終為IdNameVM類,那么您的實現應為:

//The Method declaration of T type
private IdNameVM  HydrateEntityToVM<T>(T projectValue)
{
     //Checking whether the object exists or not
     //if null than return the default value of IdNameVM
     if(projectValue == null) return default(IdNameVM);  

     //Checking if we are supporting the implementation or not for that class
     //In your case YourStrongTypeClass is ProjectValue Class
     if(projectValue is YourStrongTypeClass) 
     {

         //Casting the T object to strong type object
         var obj = projectValue as YourStrongTypeClass;

         return new IdNameVM()
         {
            Id = obj.Id,
            Name = obj.Name
         };
     } 
     else
     {
        //The else statement is for if you want to handle some other type of T implementation
        throw new NotImplementedException($"The type {typeof(T)} is not implemented");
     }
}

我喜歡內維爾·納澤拉內(Neville Nazerane)的回答,因為它消除了反思的需要。 但是,如果您確實想使用反射來做到這一點,那么即使找不到匹配的Id或Name屬性,下面也是一種構造結果的可行方法。

請注意,在此示例中,我沒有添加任何檢查I和Name屬性的類型在T和TResult之間是否匹配。

   public static TResult HydrateEntityToVM<T, TResult>(T inputValue, TResult resultValue) where T : class 
    {
        if (inputValue == null || resultValue == null)
            return default(TResult);

        var idValue = inputValue.GetType().GetProperty("Id").GetValue(inputValue);
        var nameValue = inputValue.GetType().GetProperty("Name").GetValue(inputValue);

        object instance;
        if (resultValue == null)
        {
            var ctor = resultValue.GetType().GetConstructor(Type.EmptyTypes);
            instance = ctor.Invoke(new object[] {});
        }
        else
        {
            instance = resultValue;
        }

        var idProp = instance.GetType().GetProperty("Id");
        if (idProp != null)
        {
            if (idProp.CanWrite)
                idProp.SetValue(instance, idValue);
        }

        var nameProp = instance.GetType().GetProperty("Name");
        if (nameProp != null)
        {
            if (nameProp.CanWrite)
                nameProp.SetValue(instance, nameValue);
        }

        return (TResult) instance;
    }

暫無
暫無

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

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