繁体   English   中英

C#实例化后更改通用对象?

[英]C# Change generic object after it is instantiated?

在实例化SomeClass之后是否可以将TEntity更改为NewEntity?

例如,使用以下类定义:

public class SomeClass<TEntity> where TEntity : class
{
   public void ChangeSet<NewEntity>()
    {
        TEntity = NewEntity;//not valid
    }
 }

实例化如下:

var sc = new SomeClass<SomeEntity>();

我怎么能做到这一点?

sc.ChangeSet<NewEntity>();

在实例化SomeClass之后是否可以将TEntity更改为NewEntity?

,这是不可能的。 CLR如何知道如何将值从TEntity映射到SomeEntity 它们是不同的类型。 这就像要求您的杂货店将一个苹果变成一个橘子。

不建议使用以下代码。 您有许多问题需要担心,并且容易出现错误。 我将其作为您要求CLR做什么的示例。

SomeClass<Foo> fooClass = new SomeClass<Foo>():
//do stuff to fooClass
SomeClass<Baz> = fooClass.ChangeSet<Baz>();

public class SomeClass<T> where T : class
{
    public SomeClass<K> ChangeSet<K>() where K:class
    {
       var changed = new SomeClass<K>();
       //manually map the properties over
       //but how do you know that Foo.PropertyA fits into Baz.PropetyZed?
       //what happens if Foo.A has a string length of 100, but Baz.A has a max length of 50? What do you do?
       //What id Foo.ID is an INT and Baz.ID is a GUID?
       return changed;
    }
}

泛型用于在编译时强制类型安全。 最好将new SomeClass<SomeEntity>()视为实际的类本身。 实际上,它被编译为一个类。 您可以根据以下泛型类中的静态字段示例看到以下内容:

public class GenericTest<T> where T : class   
{
    public static int StaticIntField { get; set; }

    public GenericTest(int setGenericIntField)
    {
        StaticIntField = setGenericIntField;
    }
}

用这个测试:

var stringTest =new  GenericTest<string>(1);
var objectTest = new GenericTest<object>(2);

System.Diagnostics.Debug.Print(GenericTest<string>.StaticIntField.ToString()); //<-- prints 1
System.Diagnostics.Debug.Print(GenericTest<object>.StaticIntField.ToString()); //<-- prints 2
System.Diagnostics.Debug.Print(GenericTest<Control>.StaticIntField.ToString()); //<-- prints 0 because we haven't created an instance of this type yet

您是否正在尝试将一组TEntity对象转换为一组NewEntity对象? 如果是这样,那是有可能的,但是您还没有选择正确的语法来做到这一点。

那是我所追求的大部分,是的。 你能详细说一下吗?

假设您有一个通用类C<T> ,它表示一组T实例,并且您想将其转换为通用类C<U>的实例; 一组U实例。 您不能更改C<T>实例的类型,但是可以创建一个类型为C<U>的新对象。 签名将是:

public class C<T>
{
    public C<U> Convert<U>()
    {
        C<U> result = new C<U>();
        // populate the result somehow
        return result;
    }
}

为了提供一种实现,进一步假设用于将一组T实例转换为一组U实例的机制是将每个T转换为U 您可以提供Func<T, U>来实现转换。 我们还将为C<T>提供一个构造函数,该构造函数使用IEnumerable<T>填充集合:

public class C<T>
{
    IEnumerable<T> _items;
    public C(IEnumerable<T> items)
    {
        _items = items;
    }
    public C<U> Convert<U>(Func<T, U> convertElement)
    {
        return new C<U>(_items.Select(convertElement));
    }
}

我们可以按原样使用它,尽管在这一点上,我们所做的只是在linq周围放了一个笨拙的包装对象:

void DoSomething()
{
    var integersOneToTen = Enumerable.Range(1, 10);
    var myClassOfIntegers = new C<int>(integersOneToTen);

    Func<int, string> converter = i => i.ToString();

    var myClassOfStrings = myClassOfIntegers.Convert<string>(converter); // the compiler can infer the type argument, but I've included it to reduce ambiguity.
}

其中一些可能与您的需求不符; 如果是这样,请发表评论,我将尝试相应地进行调整。

通用参数是该类的编译时间模板。 因此,当您将SomeClass<TEntity>实例化为SomeClass<int> ,您或多或少地告诉编译器您具有“应用于Int的某些类”的类型。

现在,在运行时,您希望能够将“应用于int的某些SomeClass”重新定义为“应用于{whatever}的某些SomeClass”。 但是,“应用于零件”需要在编译时指定,因此您不能这样做。

另一种思考的方式是想象这是否已普遍实施。 例如,想象一下int上的ChangeSet<T>方法,有人可能突然将您的int变成字符串或对象或Foos。 请注意,不要强制转换它们,而是在运行时更改int的类定义。 哎呀!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM