[英]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
};
}
創建通用方法時,必須牢記一些規則
讓我們以上述示例為例:您需要一個名稱為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.