Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用额外属性扩展类_C#_Dynamic_Reflection - Fatal编程技术网

C# 如何使用额外属性扩展类

C# 如何使用额外属性扩展类,c#,dynamic,reflection,C#,Dynamic,Reflection,假设我有一个名为Foo的类 我无法更改Foo类,但我不想使用类型为string的名为Bar的属性对其进行扩展 我还有很多类,比如Foo,所以我对“通用”解决方案感兴趣 我正在研究ExpandoObject,dynamic,它给出了我想要的结果,但我想知道它是否可以不使用dynamic static void Main(string[] args) { var foo = new Foo() { Thing = "this" }; var fooplus = Merge(foo,

假设我有一个名为
Foo
的类

我无法更改
Foo
类,但我不想使用类型为
string
的名为
Bar
的属性对其进行扩展

我还有很多类,比如
Foo
,所以我对“通用”解决方案感兴趣

我正在研究
ExpandoObject
dynamic
,它给出了我想要的结果,但我想知道它是否可以不使用
dynamic

static void Main(string[] args)
{
    var foo = new Foo() { Thing = "this" };
    var fooplus = Merge(foo, new { Bar = " and that" });
    Console.Write(string.Concat(fooplus.Thing, fooplus.Bar));
    Console.ReadKey();
}

public class Foo
{
    public string Thing { get; set; }
}

public static dynamic Merge(object item1, object item2)
{
    if (item1 == null || item2 == null)
    return item1 ?? item2 ?? new ExpandoObject();

    dynamic expando = new ExpandoObject();
    var result = expando as IDictionary<string, object>;
    foreach (System.Reflection.PropertyInfo fi in item1.GetType().GetProperties())
    {
        result[fi.Name] = fi.GetValue(item1, null);
    }
    foreach (System.Reflection.PropertyInfo fi in item2.GetType().GetProperties())
    {
        result[fi.Name] = fi.GetValue(item2, null);
    }
    return result;
}
static void Main(字符串[]args)
{
var foo=new foo(){Thing=“this”};
var fooplus=Merge(foo,new{Bar=“and that”});
Write(string.Concat(fooplus.Thing,fooplus.Bar));
Console.ReadKey();
}
公开课Foo
{
公共字符串对象{get;set;}
}
公共静态动态合并(对象项1、对象项2)
{
if(item1==null | | item2==null)
返回item1??item2??新的expandooobject();
动态expando=新的ExpandoObject();
var结果=作为IDictionary的expando;
foreach(item1.GetType().GetProperties()中的System.Reflection.PropertyInfo-fi)
{
结果[fi.Name]=fi.GetValue(item1,null);
}
foreach(item2.GetType().GetProperties()中的System.Reflection.PropertyInfo-fi)
{
结果[fi.Name]=fi.GetValue(item2,null);
}
返回结果;
}

在没有访问类定义的情况下,最好创建一个从目标类派生的类。除非原始代码是密封的

,否则通过使用Reflection.Emit和运行时代码生成可以相对轻松地解决问题

假设现在您有以下要扩展的类

public class Person
{
    public int Age { get; set; }
}
此类表示一个人,并包含一个名为Age的属性来表示该人的年龄

在您的情况下,您还希望添加一个string类型的Name属性来表示此人的姓名

最简单、最精简的解决方案是定义以下接口

public interface IPerson
{   
    string Name { get; set; }
    int Age { get; set; }
}
class DynamicExtension<T>
{
    public K ExtendWith<K>()
    { 
        var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Assembly"), AssemblyBuilderAccess.Run);
        var module = assembly.DefineDynamicModule("Module");
        var type = module.DefineType("Class", TypeAttributes.Public, typeof(T));

        type.AddInterfaceImplementation(typeof(K));

        foreach (var v in typeof(K).GetProperties())
        {
            var field = type.DefineField("_" + v.Name.ToLower(), v.PropertyType, FieldAttributes.Private);
            var property = type.DefineProperty(v.Name, PropertyAttributes.None, v.PropertyType, new Type[0]);
            var getter = type.DefineMethod("get_" + v.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual, v.PropertyType, new Type[0]);
            var setter = type.DefineMethod("set_" + v.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual, null, new Type[] { v.PropertyType });

            var getGenerator = getter.GetILGenerator();
            var setGenerator = setter.GetILGenerator();

            getGenerator.Emit(OpCodes.Ldarg_0);
            getGenerator.Emit(OpCodes.Ldfld, field);
            getGenerator.Emit(OpCodes.Ret);

            setGenerator.Emit(OpCodes.Ldarg_0);
            setGenerator.Emit(OpCodes.Ldarg_1);
            setGenerator.Emit(OpCodes.Stfld, field);
            setGenerator.Emit(OpCodes.Ret);

            property.SetGetMethod(getter);
            property.SetSetMethod(setter);

            type.DefineMethodOverride(getter, v.GetGetMethod());
            type.DefineMethodOverride(setter, v.GetSetMethod());
        }

        return (K)Activator.CreateInstance(type.CreateType());
    }
}
此接口将用于扩展类,它应包含当前类包含的所有旧属性以及要添加的新属性。原因很快就会弄清楚

现在,您可以使用下面的类定义,通过在运行时创建一个新类型来实际扩展您的类,该类型也将使它从上述接口派生

public interface IPerson
{   
    string Name { get; set; }
    int Age { get; set; }
}
class DynamicExtension<T>
{
    public K ExtendWith<K>()
    { 
        var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Assembly"), AssemblyBuilderAccess.Run);
        var module = assembly.DefineDynamicModule("Module");
        var type = module.DefineType("Class", TypeAttributes.Public, typeof(T));

        type.AddInterfaceImplementation(typeof(K));

        foreach (var v in typeof(K).GetProperties())
        {
            var field = type.DefineField("_" + v.Name.ToLower(), v.PropertyType, FieldAttributes.Private);
            var property = type.DefineProperty(v.Name, PropertyAttributes.None, v.PropertyType, new Type[0]);
            var getter = type.DefineMethod("get_" + v.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual, v.PropertyType, new Type[0]);
            var setter = type.DefineMethod("set_" + v.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual, null, new Type[] { v.PropertyType });

            var getGenerator = getter.GetILGenerator();
            var setGenerator = setter.GetILGenerator();

            getGenerator.Emit(OpCodes.Ldarg_0);
            getGenerator.Emit(OpCodes.Ldfld, field);
            getGenerator.Emit(OpCodes.Ret);

            setGenerator.Emit(OpCodes.Ldarg_0);
            setGenerator.Emit(OpCodes.Ldarg_1);
            setGenerator.Emit(OpCodes.Stfld, field);
            setGenerator.Emit(OpCodes.Ret);

            property.SetGetMethod(getter);
            property.SetSetMethod(setter);

            type.DefineMethodOverride(getter, v.GetGetMethod());
            type.DefineMethodOverride(setter, v.GetSetMethod());
        }

        return (K)Activator.CreateInstance(type.CreateType());
    }
}
DynamicExtension类定义现在更改为以下内容

public interface IPerson
{
    string Name { get; set; }

    Person Person { get; set; }
}
class DynamicExtension<T>
{
    public T Extend()
    {
        var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Assembly"), AssemblyBuilderAccess.Run);
        var module = assembly.DefineDynamicModule("Module");
        var type = module.DefineType("Class", TypeAttributes.Public);

        type.AddInterfaceImplementation(typeof(T));

        foreach (var v in typeof(T).GetProperties())
        {
            var field = type.DefineField("_" + v.Name.ToLower(), v.PropertyType, FieldAttributes.Private);
            var property = type.DefineProperty(v.Name, PropertyAttributes.None, v.PropertyType, new Type[0]);
            var getter = type.DefineMethod("get_" + v.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual, v.PropertyType, new Type[0]);
            var setter = type.DefineMethod("set_" + v.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual, null, new Type[] { v.PropertyType });

            var getGenerator = getter.GetILGenerator();
            var setGenerator = setter.GetILGenerator();

            getGenerator.Emit(OpCodes.Ldarg_0);
            getGenerator.Emit(OpCodes.Ldfld, field);
            getGenerator.Emit(OpCodes.Ret);

            setGenerator.Emit(OpCodes.Ldarg_0);
            setGenerator.Emit(OpCodes.Ldarg_1);
            setGenerator.Emit(OpCodes.Stfld, field);
            setGenerator.Emit(OpCodes.Ret);

            property.SetGetMethod(getter);
            property.SetSetMethod(setter);

            type.DefineMethodOverride(getter, v.GetGetMethod());
            type.DefineMethodOverride(setter, v.GetSetMethod());
        }

        var instance = (T)Activator.CreateInstance(type.CreateType());

        foreach (var v in typeof(T).GetProperties().Where(x => x.PropertyType.GetConstructor(new Type[0]) != null))
        {
            instance.GetType()
                    .GetProperty(v.Name)
                    .SetValue(instance, Activator.CreateInstance(v.PropertyType), null);
        }

        return instance;
    }
}
类动态扩展
{
公共电话号码(续)
{
var assembly=AppDomain.CurrentDomain.DefinedDynamicAssembly(新的AssemblyName(“assembly”),AssemblyBuilderAccess.Run);
var模块=组件。定义动态模块(“模块”);
var type=module.DefineType(“Class”,TypeAttributes.Public);
类型。AddInterfaceImplementation(类型(T));
foreach(typeof(T).GetProperties()中的变量v)
{
var field=type.DefineField(“\u3”+v.Name.ToLower(),v.PropertyType,FieldAttributes.Private);
var property=type.DefineProperty(v.Name,PropertyAttributes.None,v.PropertyType,新类型[0]);
var getter=type.DefineMethod(“get_”+v.Name,MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual,v.PropertyType,新类型[0]);
var setter=type.DefineMethod(“set_”+v.Name,MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual,null,新类型[]{v.PropertyType});
var getGenerator=getter.GetILGenerator();
var setGenerator=setter.GetILGenerator();
getGenerator.Emit(操作码.Ldarg_0);
getGenerator.Emit(操作码.Ldfld,字段);
getGenerator.Emit(操作码.Ret);
setGenerator.Emit(操作码.Ldarg_0);
setGenerator.Emit(操作码.Ldarg_1);
setGenerator.Emit(操作码.Stfld,字段);
setGenerator.Emit(操作码.Ret);
SetGetMethod(getter);
属性。SetSetMethod(setter);
type.DefineMethodOverride(getter,v.getMethod());
type.DefineMethodOverride(setter,v.GetSetMethod());
}
var instance=(T)Activator.CreateInstance(type.CreateType());
foreach(typeof(T).GetProperties()中的var v,其中(x=>x.PropertyType.GetConstructor(新类型[0])!=null))
{
instance.GetType()
.GetProperty(v.Name)
.SetValue(实例,Activator.CreateInstance(v.PropertyType),null);
}
返回实例;
}
}
现在,我们可以简单地执行以下代码行以获得所有适当的值

class Program
{
    static void Main(string[] args)
    {
        var extended = new DynamicExtension<IPerson>().Extend();

        extended.Person.Age = 25;
        extended.Name = "Billy";

        Console.WriteLine(extended.Name + " is " + extended.Person.Age);

        Console.Read();
    }
}
类程序
{
静态void Main(字符串[]参数)
{
var extended=new DynamicExtension().Extend();
延长的个人年龄=25岁;
extended.Name=“比利”;
Console.WriteLine(extended.Name+“是”+extended.Person.Age);
Console.Read();
}
}

由于我的评论越来越冗长,我想我应该添加一个新的答案。这个答案完全是马里奥的作品和思想,只有我的小补充来说明我想表达的内容

对mario的示例进行了一些小的更改,这将使其工作得非常好,即,只需更改现有属性作为类对象添加的事实,而不是复制整个类。不管怎样,这看起来是这样的(只添加了修订的部分,其他所有部分仍然按照马里奥的回答):

对于
IPerson
接口,我们添加了实际的
Person
类,而不是复制属性:

public interface IPerson
{
    // extended property(s)
    string Name { get; set; }
    // base class to extend - tho we should try to overcome using this
    Person Person { get; set; }
}
这转化为以下各项的更新使用:

static void Main(string[] args)
{
    var extended = new DynamicExtension<Person>().ExtendWith<IPerson>();

    var pocoPerson = new Person
    {
        Age = 25,
        FaveQuotation = "2B or not 2B, that is the pencil"
    };

    // the end game would be to be able to say: 
    // extended.Age = 25; extended.FaveQuotation = "etc";
    // rather than using the Person object along the lines below
    extended.Person = pocoPerson;
    extended.Name = "Billy";

    Console.WriteLine(extended.Name + " is " + extended.Person.Age 
        + " loves to say: '" + extended.Person.FaveQuotation + "'");

    Console.ReadKey();
}
static void Main(字符串[]args)
{
var extended=new DynamicExtension().extendedwith();
var pocoPerson=新人
{
年龄=25岁,
favequote=“2B或不是2B,那是铅笔”
};
//末日
var className = "ClassA";
var baseType = typeof(List<string>);
var typeExtender = new TypeExtender(className, baseType);
typeExtender.AddProperty("IsAdded", typeof(bool));
typeExtender.AddProperty<double>("Length");
var returnedClass = typeExtender.FetchType();
var obj = Activator.CreateInstance(returnedClass);